【问题标题】:How to increase a new type and don't need to modify factory class?如何增加一个新类型而不需要修改工厂类?
【发布时间】:2018-09-16 19:34:13
【问题描述】:

当我使用工厂模式时,我有一个问题:当我有一个新类型时,我需要修改我的工厂类。比如:

Animal.java:

public interface Animal {
    void eat();
}

狗.java:

public class Dog implements Animal {
    ...
    @Override
    public void eat(){
        System.out.println("eat bones");
    }
}

猫.java

public class Cat implements Animal {
    ...
    @Override
    public void eat(){
        System.out.println("eat fish");
    }
}

现在我有了一个 Animal 接口和两个 Animal 类,然后我的工厂就在这里了:

public class AnimalFactory {
    public static final int Dog = 1;
    public static final int Cat = 2;

    public static Animal getAnimal(int type) {
        switch(type) {
           case Dog: return new Dog();
           case Cat: return new Cat();
           default: return null;
        }
    }
}

这很简单,但是如果我有一个新类型 Mouse ,我必须修改我的工厂以添加类似 case Mouse: return new Mouse 的 case 语句。

那么,有没有办法增加新类型而不需要修改我的工厂类?

【问题讨论】:

  • 工厂可能有许多不同的实现。通过这个实现,是的,你必须修改工厂类。 OTOH,如果您的工厂使用反射来查找和设置动物,那么 yiu 可能不需要更改它。
  • 您为什么要这样做?我知道这可能不是您想要的答案,但这不是如何使用工厂。至少使用枚举或类引用。无论如何......为什么你不想为每种类型都有特定的方法,任何其他的你都没有运行时安全。
  • 我知道这个问题很低,而且我很弱。我只是想知道当我增加一个类型时该怎么做,我不需要修改任何东西,只需添加一个新的类。
  • @JackyWong 你想到了哪种工厂模式?有许多。您有我们可以查看的链接或特定来源吗?

标签: java design-patterns factory-pattern


【解决方案1】:

要创建一个不需要为每个添加/删除的Animal 类型更新/修改的工厂,您必须将检索Animal 类及其工厂标识符的逻辑提取到Animal 类本身中。 一般来说,所有动物子类都应该实现一个返回工厂标识符的方法,并且在工厂中,您应该首先从特定包中加载所有实现此接口的类。这个加载类使用reflections library 会更简单。
但是在编译时实现它既不直接也不安全可靠。
如果不维护工厂,最好使用依赖注入框架提供的工厂功能。
不再需要工厂类。

使用 Spring,Dog 可以声明为:

@Component
@Scope("prototype")
public class Dog extends Animal{..}

注意原型范围以表明每次注入都必须创建一个新实例。

从客户端你可以只注入 Animal 实例,例如:

@Autowired
private Dog dog;

或者使用显式工厂Dog dog = ApplicationContext.getBean("dog");

【讨论】:

    【解决方案2】:

    在您的情况下,您的工厂方法目前没有任何复杂的逻辑来确定应该实例化哪个类并返回它的对象 - 因此,您可以将动物类型作为整数常量传递,您也可以将 java.lang.Class<? extends Animal> animalClass 作为方法传递使用 generics 参数并使用 reflection 创建具体类的相应动物实例(看看Class.newInstance())...这将使您免于编写额外的代码每次添加新的动物类型时...

    简单的例子,你可能想处理可以在方法实现中抛出的特定异常,而不是仅仅抛出所有异常......

    Class<? extends Animal> animalClass 只允许将 Class 实例作为参数传递给您的工厂方法,这些实例是 Animal 的子类/接口实现类。

    public static Animal getAnimal(Class<? extends Animal> animalClass) throws Exception {
        return animalClass.newInstance(); 
        // >=JAVA9: return animalClass.getDeclaredConstructors().newInstance(); 
    }
    

    使用您的工厂的客户端代码:

    Animal animal = AnimalFactory.getAnimal(Dog.class);
    

    【讨论】:

      猜你喜欢
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-07
      • 1970-01-01
      • 2017-03-08
      • 1970-01-01
      相关资源
      最近更新 更多