Java 工厂模式与多态性

Java 工厂模式与多态性,java,polymorphism,factory-pattern,Java,Polymorphism,Factory Pattern,我的计划是拥有一个控制面板工厂,它将为每个不同的模型类构建一个定制的控制面板: abstact class Model { } class ModelA extends Model { } class ModelB extends Model { } 现在,我的计划是让Factory类基于方法重载传递的模型类创建不同的ControlPane实例: class ControlPaneFactory { private ControlPaneFactory() { }

我的计划是拥有一个
控制面板工厂
,它将为每个不同的
模型
类构建一个定制的
控制面板

abstact class Model {
}

class ModelA extends Model {
}

class ModelB extends Model {
}
现在,我的计划是让Factory类基于方法重载传递的
模型
类创建不同的
ControlPane
实例:

class ControlPaneFactory {
    private ControlPaneFactory() {
    }

    public static ControlPanel build(ModelA model) {
        return new ControlPaneA(model);
    }

    public static ControlPanel build(ModelB model) {
        return new ControlPaneB(model);
    }
}
然而,这是非常有问题的,因为在调用factorys方法时,我只有一个
Model
类型的变量,因此我需要首先使用
instanceof
,这是一个巨大的代码气味。同样适用于采用浓缩工厂法:

public static ControlPane build(Model model) {
    if (model instanceof ModelA) 
        return new ControlPaneA(model);
    else if (model instanceof ModelB) 
        return new ControlPaneB(model);
    else throw new IllegalArgumentException("Unsupported model");
}
我曾考虑在模型类中使用枚举来指定
model
的类型,但是这似乎也是一个违反DRY的坏选项


此外,我更希望
ControlPane
的实例化独立于
Model
类(即在spererate类中)。有没有一种“好”的方法来解决这个问题?

试图使您的代码更通用,这意味着您的控制面板不应该依赖于特定的模型。但是,如果确实有必要,您可以尝试以下方法:

public class ControlPanelFactory {
    private static Map<Class<? extends Model>, Class<? extends ControlPanel>> modelPanelMap = new HashMap<>();

    public static void addModelPaneRelation(Class<? extends Model> model, Class<? extends ControlPanel> pane) {
        modelPanelMap.put(model, pane);
    }

    public static ControlPanel build(Model model) {
        try {
            return modelPanelMap.get(model.getClass())
                    .getConstructor(model.getClass())
                    .newInstance(model);
        } catch (Exception exception) {
            // Handle exceptions
        }

        return null;
    }
}

至少这将提取面板如何依赖于模型的逻辑。同样,我认为这不是最干净的解决方案。

如果您希望所有工厂方法都在同一个对象中,那么您将以某种方式需要If组的开关/实例,或者需要一个
模型
控制面板
的映射

或者,您可以将factory方法移动到
模型
类。本质上,这是抽象工厂模式,但您正在使用
模型
对象实现它。有几种方法来看待这个问题。可以说它增加了
模型
控制面板
对之间的耦合,但我建议您尝试实现这一点。也可能有人认为,这会降低factory代码的可重用性,因为您需要一个
模型
对象来运行它,但您为factory对象提供的示例接口无论如何都需要一个内置的
模型
。随着远离贫血模型,我认为这是一种合理的实现方法,并降低了工厂对象的复杂性(如果您仍然需要的话)

我会这样说:

ControlPanelFactory.addModelPaneRelation(ModelA.class, ControlPanel.class);
abstact class Model {
    public abstract ControlPanel buildControlPanel();
}

class ModelA extends Model {
    public ControlPanel buildControlPanel() {
        return new ControlPanelA(this);
    }
}

class ModelB extends Model {
    public ControlPanel buildControlPanel() {
        return new ControlPanelB(this);
    }
}

// Don't really need this anymore...
class ControlPaneFactory {
    public static ControlPanel build(Model model) {
        return model.buildControlPanel();
    }
}
这仍然允许您在需要时为
控制面板
灵活地使用不同的构造函数,并且在程序启动时不需要注册对象映射

您可以将
buildControlPanel()
方法移出
模型
s,创建一个适当的抽象工厂模式,并从
模型
对象返回一个具体工厂。但我觉得这只会增加你的课程数量,而不会带来任何实际的改善。如果您有很多使用相同构建代码的
Model
类(如
ModelA
ModelB
ModelC
都对应于
ControlPanelX
),那么这可能是一个很好的方法,但听起来您并没有这样做


然而,归根结底,选择要实例化的具体类的switch或if语句并不是世界上最糟糕的事情。其他库也使用了类似的东西,例如。

ControlPane
的实例化移动到相应的
Model
类将是显而易见的解决方案,但正如您所说,这确实增加了视图和模型之间的耦合,这正是我试图避免的。抽象工厂肯定是杀伤力过大。我只是想知道是否有一种明显而优雅的方法可以解决这一问题,但似乎如果你想将
控制面板
模型
分离,总会有一些感觉不太优雅的东西。