从抽象工厂获取专业课程

时间:2015-12-16 07:57:49

标签: java oop design-patterns factory abstraction

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

AbstractContext:

public abstract class AbstractContext {

    public abstract  void  print();
}

ContextA:

 public class ContextA extends AbstractContext {

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

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

ContextB:

 public class ContextB extends AbstractContext {

        @Override
        public void print() {

        }

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

    }

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

AbstractFactory:

public abstract class AbstractFactory {

    public abstract AbstractContext createContext();

}

FactoryA:

public class FactoryA extends AbstractFactory {

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

}

FactoryB

public class FactoryB extends AbstractFactory {

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

}

FactoryMaker

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 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

    }
}

在第一次尝试时,我尝试使用相同的签名创建接受类的不同子类型的方法,但之后我遇到了编译错误,因为基类型与方法所期望的具体类型不匹配:

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

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

无论如何要实现我想要的目标吗?

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

修改 看来我应该给你更多细节。

想象一下,我有两个网络应用程序,两个网络应用程序都访问相同的服务业务类,但可能有不同的业务规则,因为它们是两个不同的公司。每个公司都有相同产品的变体。

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

我不想开发人员做的是告诉api例如产品和公司,api返回正确的上下文并根据业务规则初始化上下文。

我希望他们“几乎”构建一个gui来填充我正在返回的每个上下文。 当然,他们需要知道他们使用的上下文,以便在GUI和我返回的上下文之间进行绑定,但同时,他们的GUI可以有共同的UI部分。

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

我举例说明了使用不同方法的abstractContext的不同实现,因为在每个上下文中我将需要访问特定属性(最后将是相同的东西,属性是返回数据的方法)。最后,上下文将只是旧的不同数据集,常见数据将保留在abstractContext类中。

我正在尽力解释自己,这是不明确的,请告诉我。

3 个答案:

答案 0 :(得分:0)

可能是变体:

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();
    }

答案 1 :(得分:0)

我认为你有设计问题。工厂返回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检查和强制转换来重建丢失的类型信息。但是,这不是首选的方法,因为您将类型选择移动到客户端代码,如果更改继承层次结构,它可以快速破坏。

答案 2 :(得分:0)

我认为你选择的工具太复杂了。

如果您只是想“保证每个上下文以相同的方式初始化,而不让开发人员自己进行不同的启动”封装就足够了。< / p>

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

假设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)无法实现的目标,因为在你的问题和例子的当前状态下,我没有看到它。