【问题标题】:Multiple factories inside parent factory父工厂内的多个工厂
【发布时间】:2014-07-06 11:00:13
【问题描述】:

正如你在下图中看到的我有一个在运行时创建实体的工厂模式。当我研究我的数据库时,我决定有一个学生和一个教授是“ISA”人,因为他们有一些共同的领域(比如名字和前名)。

同样,我决定“ISA”教授有常任和副教授。

在运行时,用户选择“教授”、“学生”等实体,而不是人。所以在这种情况下,我必须创建新的教授、学生等实体。同样,当用户选择教授实体时,它必须决定要创建哪种类型的教授。

到目前为止我创建的工厂的代码是这样的

public class EntityFactory {
protected String entityType;

public EntityFactory(String personType){
    this.entityType = entityType;
}

public Entity createEntity(){
    if(entityType.equalsIgnoreCase("Student")){
        return new Student();
    }
    else if(entityType.equalsIgnoreCase("Professor")){
        return new Professor();
    }
    //...
}
}

我想知道:如何“传递” Person 和 Professor 抽象实体来创建我想要的特定实体?这可行吗?还是我需要为我设置为抽象的实体创建不同的工厂?在这种情况下,我将如何将这些工厂与“父”工厂联系起来?

【问题讨论】:

  • 这家工厂的意义何在?如果我想创建一个新学生,为什么我要调用类型不安全的Student s = (Student) factory.create("Student") 而不是简单地调用Student s = new Student()
  • 因为我不知道用户将在运行时选择要创建的实体。有很多实体,而不仅仅是这 2 个。
  • @VassilisDe 没有回答@JBNizet 的问题。首先在哪里/为什么需要 Person 类型?为什么需要这种抽象?如果您在 ProfessorStudent 中只有公共字段,最好 IMO 将它们分组到可重用的值对象(AddressName 等)中,而不是盲目地抓住这个机会来创建基类。
  • @guillaume31 我不确定我是否完全理解 IMO 的意思......

标签: java design-patterns abstract-factory


【解决方案1】:

老实说,我不确定我是否正确理解了您的问题。

第 1 部分:您想“传递”创建 PersonProfessor 实体,因为它们是抽象的,即它们并不真正存在于数据库中,只是用于基类的目的。

我能想到的一件事是通过使用enum 而不是String 来识别entityType,以防止您工厂的用户请求这些实体类型。这个enum 将只包含可以实际创建的东西,即不是PersonProfessor

第 2 部分:或者我是否需要为我设置为抽象的实体创建不同的工厂?在这种情况下,我将如何将这些工厂与“父”工厂联系起来?

从技术上讲,您不需要创建单独的工厂,它应该取决于创建这些对象的复杂程度。如果是复杂的,如果不能泛化就应该拆分。

您可以将其拆分为多个工厂(或类似的东西)的方法是使用策略模式 (http://en.wikipedia.org/wiki/Strategy_pattern),该模式使用请求的 entityType 作为上下文来选择要使用的策略——该策略可以成为该特定类型的专业工厂。

如果你的PersonProfessor 类型在Java 意义上真的是抽象,那么你就不能实例化它们,这意味着不可能有父工厂。我猜你可能会在 Person 的构造函数中实现所有内容,或者使用某种初始化方法。

希望这可以让你向前迈出一步:)

更新:第一步是在您的创建方法中使用带有枚举值的 switch 语句

public enum EntityType {
    STUDENT,
    ABIDING_PROF,
    DEPUTY_PROF

    // ...
}

public class EntityFactory {
    private final EntityType entityType;

    public EntityFactory(EntityType entityType) {
        this.entityType = entityType;
    }

    public Entity createEntity() {
        switch (entityType) {
            case STUDENT:
                return new Student(); // or some more sophisticated construction logic

            case DEPUTY_PROF:
                return new DeputyProfessor(); // .. or something else

            // ...
        }
    }
}

当然,您需要将用户在某个位置输入到用户界面的内容映射到枚举值,但这应该很容易实现,并且您可以使用适当的 UI 组件来禁止错误类型(假设是一个组合框只包含允许的内容)。

【讨论】:

  • 枚举可能对我有用。如果我理解你的意思,我必须创建一个enum = {Student, Abiding_prof, Deputy_prof}。我不得不承认我对枚举不太了解......我将如何更改 creatEentity() 方法以使用枚举?
  • 由于格式在 cmets 中不起作用,我已经更新了我的原始帖子 :)
  • 谢谢@PermaFrost 我真的很感激
【解决方案2】:

在我看来,你确实首先需要在这里建厂。将其视为基于给定前提条件的创建策略:必须存在一个级别(可能是您的 UI),用户在其中明确指定他或她想要什么。所以你需要的只是() -> Entity函数的不同实现(C#版本是Entity Create() {})。解决此类问题有两种常见的方法:AbstractFactory - 工厂的工厂,更高阶的工厂,或普通的 Strategy 模式(也适用于 State 模式,其中实际状态是选择由用户)。

无论如何,最终您都会得到() -> Entity 签名,即使它会在您的代码中明确定义。似乎Func<Entity>Func<Task<Entity>> 是最紧凑但可重用和可测试的类型。不过,自定义 IEnitityBuilder 也可以。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-01
    • 1970-01-01
    • 2011-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多