从抽象工厂获得专业化 class

Get specialized class from Abstract Factory

我有三个 classes,AbstractContext、ContextA 和 ContextB,我想在创建方面进行概括,但我想在不同的上下文中访问每个方法的特定方法。

抽象上下文:

public abstract class AbstractContext {

    public abstract  void  print();
}

上下文A:

 public class ContextA extends AbstractContext {

        @Override
        public void print() {
            System.out.println("In context A");
        }

        public void doSomeA(){
            System.out.println("Do some A");
        }
    }

上下文 B:

 public class ContextB extends AbstractContext {

        @Override
        public void print() {

        }

        public void doSomeB(){
            int a=1;
            System.out.println(a);
        }

    }

我实现了抽象工厂模式,因此我可以概括这些 classes 的创建:

抽象工厂:

public abstract class AbstractFactory {

    public abstract AbstractContext createContext();

}

工厂A:

public class FactoryA extends AbstractFactory {

    @Override
    public AbstractContext createContext() {
        AbstractContext newClass = new ContextA();
        return newClass;
    }

}

工厂 B

public class FactoryB extends AbstractFactory {

    @Override
    public AbstractContext createContext() {
        AbstractContext newClass = new ContextB();
        return newClass;
    }

}

工厂制造商

public class FactoryMaker {
    private static AbstractFactory factory = null;

    public static AbstractFactory getFactory(String condition) {
        if (condition == "A") {
            factory = new FactoryA();
        } else {
            factory = new FactoryB();
        }

        return factory;
    }
}

这里的问题是,创建一个实例后,由于所有工厂return基类型我无法访问每个子class的任何具体方法class。

public class Main {

    public static void main(String[] args) {

        AbstractContext contextA = FactoryMaker.getFactory("A").createContext();
        contextA.print();    //Works fine
        contextA.doSomeA(); //Won't compile

        AbstractContext contextB = FactoryMaker.getFactory("").createContext();
        contextB.print(); //Works fine
        contextB.doSomeB(); //Won't Compile

    }
}

第一次尝试时,我尝试创建具有相同签名的方法来接受 class 的不同子类型,但随后出现编译错误,因为基类型与方法期望的具体类型不匹配:

public static void process(ContextA context){
        context.doSomeA();
}

public static void process(ContextB context){
        context.doSomeB();
}

有没有办法实现我想要做的事情?

为了给你一个额外的上下文,我正在创建一个 Java 共享库 (API),它将被其他开发人员使用,我正在尝试做的是找到一种方法开发人员可以从我的 API 那里以标准方式获得他们想要的上下文。 我希望他们请求上下文并从那时起工作,填充每个上下文具有的属性,然后 api 将处理每个上下文的特定部分。

编辑: 看来我应该给你更多的细节。

假设我有两个 Web 应用程序,这两个 Web 应用程序访问相同的服务业务 classes,但可能有不同的业务规则,因为两个不同的 companies.Each 公司有相同产品的变体。

我想要实现的目标是制作一个 API 内部将为开发人员提供繁重的通用代码。

我不希望开发人员做的是告诉 api 例如产品和公司,以及 api return 正确的上下文并根据业务规则。

我希望他们 "almost" 构建一个 gui 来填充我正在 return 的每个上下文。 当然,他们需要知道他们使用的上下文,以便在 GUI 和上下文 i return 之间进行绑定,但与此同时,他们的 GUI 可以有共同点UI 份。

我也在更新内容,目前,我所做的是创建一个 ContextHolder,return 是开发人员想要的上下文,但它看起来不太好,因为公司可以扩展产品线或每种产品的变体。

我给出了使用不同方法的 abstractContext 的不同实现的例子,因为在每个上下文中我都需要访问特定的属性(最终将是同一件事,属性是方法 returning 数据).最后,contexts 只会旧不同的数据集,公共数据将留在 abstractContext class.

我正在尽力解释自己,如果不够清楚,请告诉我。

可能是变体:

public interface Context {

    void print();

}


public class ContextHolder<T extends Context> {

    private T context;

    public ContextHolder(T context) {
        this.context = context;
    }

    public T getContext() {
        return context;
    }

    public void print() {
        context.print();
    }

    public void foo() {

    }

}


public class ContextA implements Context {

    @Override
    public void print() {
        System.out.println("In context A");
    }

    public void doSomeA() {
        System.out.println("Do some A");
    }
}


public class ContextB implements Context {

    @Override
    public void print() {

    }

    public void doSomeB() {
        int a = 1;
        System.out.println(a);
    }

}

public abstract class AbstractFactory<T extends Context> {

    public abstract ContextHolder<T> createContext();

}

public class FactoryA extends AbstractFactory<ContextA> {

    @Override
    public ContextHolder<ContextA> createContext() {
        return new ContextHolder<ContextA>(new ContextA());
    }

}

public class FactoryB extends AbstractFactory<ContextB> {

    @Override
    public ContextHolder<ContextB> createContext() {
        return new ContextHolder<ContextB>(new ContextB());
    }

}

public class FactoryMaker {

    private static AbstractFactory factory = null;

    public static AbstractFactory getFactory(String condition) {
        if (condition == "A") {
            factory = new FactoryA();
        } else {
            factory = new FactoryB();
        }

        return factory;
    }
}


 public static void main(String[] args) {
        ContextHolder<ContextA> contextHolderA = FactoryMaker.getFactory("A").createContext();
        contextHolderA.print();    
        contextHolderA.getContext().doSomeA();

        ContextHolder<ContextB> contextHolderB = FactoryMaker.getFactory("").createContext();
        contextHolderB.print(); 
        contextHolderB.getContext().doSomeB();
    }

我认为你的设计有问题。工厂returns一个AbstractContext,但显然这种类型对客户来说是不够的。我建议重新考虑 AbstractContext API 或引入一个接口。在这两种情况下,您都必须为两种上下文找到一个摘要 api。

否则....如果你不能那样做,你必须通过使用

来重建丢失的类型信息

访问者模式方法

 public interface ContextVisitor {
       public void visit(ContextA contextA);
       public void visit(ContextB contextB);
 }

public abstract class AbstractContext {
    public abstract  void  print();
    public abstract void accept(ContextVisitor contextVisitor);
}

public class ContextA extends AbstractContext {
   ....
   public void accept(ContextVisitor contextVisitor){
       contextVisitor.visit(this);
   }
}

模式用法

 ContextVisitor cv = new ContextVisitor(){

   public void visit(ContextA contextA){
       contextA.print();  
       contextA.doSomeA(); 
   }

   public void visit(ContextB contextB){
       contextB.print();
       contextB.doSomeB(); 
   }

 }

 AbstractContext contextA = FactoryMaker.getFactory("A").createContext();
 contextA.accept(cv);
 AbstractContext contextB = FactoryMaker.getFactory("").createContext();
 contextB.accept(cv);

适配器模式方法

public abstract class AbstractContext {
    public abstract  void  print();
    public abstract <T extends AbstractContext> T getAdapter(Class<T> type);
}


public class ContextA extends AbstractContext {
   ....
   public <T extends AbstractContext> T getAdapter(Class<T> type) {
       if(type.isInstance(this)){
           return type.cast(this);
       }
       return null;
   }
}

适配器模式用法:

 AbstractContext contextA = FactoryMaker.getFactory("A").createContext();
 ContextA contextA = contextA.getAdapter(ContextA.class);
 if(contextA != null){
     contextA.print();  
     contextA.doSomeA(); 
 }

如果这两种方法都不适用于您的情况,您只能使用 instanceof 检查和强制转换来重建丢失的类型信息。但这不是首选方式,因为您将类型选择移至客户端代码,并且如果更改继承层次结构,它可能会很快被破坏。

我认为你为这项工作选择了一个过于复杂的工具。

如果只是想"guarantee each context is initialized the same way, and not having the developers to make the different initilization themselves"封装就够了

这个基本的面向对象原则允许您将实现细节隐藏在一个对象中,这似乎正是您所需要的。

假设ContextA仍然扩展AbstractContext,比较这个(1)

ContextA contextA = new ContextA();
contextA.print();   //Works fine
contextA.doSomeA(); //Works fine

使用您之前的代码 (2)

AbstractContext contextA = FactoryMaker.getFactory("A").createContext();
contextA.print();    //Works fine
contextA.doSomeA(); //Won't compile

请告诉我们 (2) 中有哪些是您无法通过 (1) 实现的,因为在您的问题和示例的当前状态下,我看不到它。