抽象工厂设计模式和泛型-Java

时间:2019-01-27 13:41:52

标签: java generics design-patterns abstract-factory

这是我第一次使用this design pattern,但遇到了一些困难。以这张图片为参考:

enter image description here

我有两个要创建工厂的 AbstractProduct ,因为它们来自不同的“家庭”。其中一种产品是另一种产品的集合。

public abstract class Frame{
    ...
}

public abstract class FrameMap<F extends Frame>{
    protected TreeMap<Integer, F> map;

    public F readByKey(Integer key){
        return this.map.get(key);
    }

    public void put(Integer key, F frame){
        this.map.put(key,frame);
    }
    ...
}

请注意,FrameMapF的集合(为简单起见,我省略了大多数其他方法),因此它需要能够获取和放置元素。 以一个家庭为例(App1的一个),这些是具体的 Product

public class App1Frame extends Frame{
    ...
}

public class App1FrameMap extends FrameMap<App1Frame>{
    ...
}

然后我创建了 AbstractFactory

public abstract class ApplicationFactory{
    //Frame factory methods
    public abstract Frame makeFrame();

    //FrameMap factory methods
    public abstract FrameMap<? extends Frame> makeFrameMap();
}

和App1的 ConcreteFactory

public class App1Factory extends ApplicationFactory{
    //Frame factory methods
    public Frame makeFrame(){
        return new App1Frame();
    }

    //FrameMap factory methods
    public FrameMap<App1Frame> makeFrameMap(){
        return new App1FrameMap();
    }
}

所有这些都可以编译,但是我不太喜欢它,因为我的客户无法执行以下操作:

ApplicationFactory factory = new App1Factory();
FrameMap<Frame> frameMap = factory.makeFrameMap(); //This doesn't compile!

至少在概念上是模式的目标,即让客户端仅使用抽象类。为了使其正常工作,我必须执行以下操作:

App1Factory factory = new App1Factory();
FrameMap<App1Frame> frameMap = factory.makeFrameMap(); //This compiles!

这似乎与使用设计模式的目的背道而驰。

您是否知道在我的情况下实现此模式的更好方法,即在AbstractProduct中使用泛型,以便让Client只使用抽象类而又不知道底层实现?

2 个答案:

答案 0 :(得分:0)

您可以将通用类型添加到ApplicationFactory

public class MainJava {
    interface Frame{}
    interface FrameMap<T extends Frame>{}

    static class App1Frame implements Frame{}
    static class App2Frame implements Frame{}
    static class App1FrameMap implements FrameMap<App1Frame>{}
    static class App2FrameMap implements FrameMap<App2Frame>{}

    interface ApplicationFactory<T extends Frame> {
        T makeFrame();
        FrameMap<T> makeFrameMap();
    }

    static class App1Factory implements ApplicationFactory<App1Frame> {
        @Override public App1Frame makeFrame() {
            return new App1Frame();
        }
        @Override public FrameMap<App1Frame> makeFrameMap() {
            return new App1FrameMap();
        }
    }

    public static void main(String... args) {
        ApplicationFactory<? extends Frame> factory = new App1Factory();
        Frame frame = factory.makeFrame();
        FrameMap<? extends Frame> map = factory.makeFrameMap();
    }
}

还要注意,ApplicationFactory对象应该injected进入客户端。如果客户端直接调用new App1Factory(),则没有指向抽象的意义。客户端在创建App1Factory之后也可以使用它。

答案 1 :(得分:0)

在@ jaco0646解决方案中,有一种简单的方法可以解决将新创建的框架添加到地图的问题,即使您在运行时不知道实际的子类型或“家庭”。只要您可以将frame和frame-map类型参数都绑定为在这样的方法中具有相同的值:

public static <T extend Frame> FrameMap<T> makeAndAdd(final AbstractFactory<T> factory) {
    T frame = factory.makeFrame();
    FrameMap<T> map = factory.makeFrameMap();
    map.add(frame);
    return map;
}

当不可能将两个动作都放在同一方法中时(例如,在不同的服务器调用中异步发生)。您仍然可以通过使用带有类型参数的另一个类来实现这种联系,这些类具有不同的操作方法……这有点复杂,需要针对实际问题进行量身定制,但是想法是相同的在某种意义上说,您是在运行时使用类型参数来绑定给不同对象的类型参数值。