工厂模式动态方法

时间:2013-08-14 15:27:08

标签: java design-patterns

我正在尝试了解工厂模式。如果有很多实现,那么我的工厂模式会有很多if else或switch情况。每次我介绍一个新的实现时,我都应该更改我的工厂代码

如下面的例子中假设狗鸭正在实施宠物界面,如果许多动物实施宠物界面,如果代码或转换案例,我工厂会用很多其他方式来实现宠物界面。有没有办法通过带来更多动态方法来解决这个问题?

package com.javapapers.sample.designpattern.factorymethod;

//Factory method pattern implementation that instantiates objects based on logic
public class PetFactory {

    public Pet getPet(String petType) {
        Pet pet = null;

        // based on logic factory instantiates an object
        if ("bark".equals(petType))
            pet = new Dog();
        else if ("quack".equals(petType))
            pet = new Duck();
        return pet;
    }

如果动物生长

if ("bark".equals(petType))
    pet = new Dog();
else if ("quack".equals(petType))
    pet = new Duck();
else if ("mno".equals(petType))
    pet = new MNO();
else if ("jkl".equals(petType))
    pet = new JKL();
else if ("ghi".equals(petType))
    pet = new GHI();
else if ("def".equals(petType))
    pet = new DEF();
......
else if ("abc".equals(petType))
    pet = new ABC();
return pet

5 个答案:

答案 0 :(得分:22)

我认为有一种动态的方法:

  1. 在您的工厂,您需要Map<String, Class<? extends Pet>>
  2. 在扩展Pet的每个类的静态构造函数中,使用这样的map注册它。
  3. 创建一个类只是map.get(pet).newInstance(当然你必须检查空值)

答案 1 :(得分:10)

工厂模式背后的想法是让你动态地实例化你在设计时不必知道的类型的对象。

有一个很大的if阻挡了这个目的。

实现此模式的有效方法是为每种类型都有一个工厂,它实现了一个基本工厂接口,并且能够实例化该类型的新对象(顺便说一下,在Java中,内置Class就是这样一个工厂的例子。)

然后注册名称/ ids / etc的地图。在运行时对这些单独工厂的实例。如果有时间实例化其中一种类型,您可以按名称在地图中查找工厂,并使用它来实例化该类型的新对象。

如何在地图中注册个别工厂完全无人问津。您可以明确注册一些,也可以扫描配置文件等。

基本上,您希望将if块替换为在运行时动态创建的映射。

您甚至不需要单独使用预先注册的&#34;地图&#34; - 有时可能适合弄清楚如何动态创建具有给定名称的对象,或两者的组合(例如Class.forName()搜索类路径,如果它已经找不到类加载)。关键是可以将名称转换为类类型,而基本工厂实际上不知道类类型是什么。

值得注意的是,Java反射已经通过Class.forName()和/或Class.newInstance()提供了非常可行的工厂实现,因此如果有意义,请考虑使用它而不是重新发明轮子。< / p>

答案 2 :(得分:3)

使用反射

public Pet getPet(String petType)
{
     Pet _pet = (Pet)Class.forName(petType).newInstance();
     return _pet;
}

你需要将你的论点从'bark','quack'改为'Dog'和'Duck'等等

答案 3 :(得分:1)

由于我遇到了类似的问题,我一直在摸不着头脑,最后我找到了一个基于Reflections Library的解决方案(注意思考中的最终S!)

它可以应用于您的问题如果您的所有宠物子类都具有可用于区分它们的属性,例如

   public String petType;

您工厂的方法可能如下:

        public static Pet getPet(String _petType) {
    String packageName = "your.package.with.pet.classes";

    Reflections reflections = new Reflections(packageName);

    Set<Class<? extends Pet>> allPets = reflections
            .getSubTypesOf(Pet.class);

    Iterator<Class<? extends Pet>> it = allPets.iterator();

    while (it.hasNext()) {
        try {
            Pet pet = it.next().newInstance();
            if (pet.petType.equals(_petType))
                return pet;
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    System.out.println("Pet " + _petType
            + " not yet implemented in package " + packageName);
    return null;
}

如果定义了新宠物,此方法将不受影响。

优点:

  • 它不需要对Pet子类进行进一步修改,也不需要对Factory维护的Map结构进行任何类型的初始化/注册

  • 它比基于Java Reflection API的解决方案更通用,因为您可以在某些属性而不是类名上区分Pet子类

缺点:

  • 它创建所有Pet子类的本地实例以找到合适的子类。在这方面,我确信这种方法可以改进。

答案 4 :(得分:1)

在Java8中,有一个Supplier接口,很好地支持了这一点。可以避免反思和手动调用,并且可以使用更简洁的方法。

类似这样的工厂:

public class DynamicSupplierTierFactory {

    public static final Map<String, Supplier<? extends Tier>> registeredSuppliers = new HashMap<>();

    static {
        registeredSuppliers.put("blue", new BlueSupplier());
        registeredSuppliers.put("silver", new SilverSupplier());
        registeredSuppliers.put("golden", new GoldenSupplier());
    }

    public static void registerSupplier(String type, Supplier<? extends Tier> supplier){
        registeredSuppliers.put(type, supplier);
    }

    public static Tier getTier(String type){
        Supplier<? extends Tier> supplier = registeredSuppliers.get(type);
        return supplier != null ? supplier.get():null;
    }
}

供应商将像:

public class BlueSupplier implements Supplier<Tier> {
    @Override
    public Tier get() {
        return new Blue();
    }
}

这可以在此处更详细地看到:https://medium.com/@mhd.durrah/factory-pattern-the-dynamic-way-with-java-8-3ca5ab48a9cf