没有if,切换实现Factory的最佳方法

时间:2015-04-08 02:38:35

标签: java design-patterns factory factory-pattern

我正在研究用Java实现Factory模式的许多方法,但仍然无法找到一个完美的方法,如果/ switch plus没有使用反射,那么它既不会受到影响。 我找到的最好的一个是Tom Hawtin的回答:https://stackoverflow.com/a/3434505/1390874

但我最关心的是它将匿名类的HashMap存储在内存中。

问题是除了Tom Hawtin的答案之外,人们还会考虑使用 Class.newInstance()? 这样可以避免我们在内存中存储不必要的匿名类吗?加上代码会更干净。

看起来像这样:

class MyFactory {
    private static final Map<String,Class> factoryMap =
        Collections.unmodifiableMap(new HashMap<String,Class>() {{
            put("Meow", Cat.class);
            put("Woof", Dog.class);
    }});

    public Animal createAnimal(String action) {
        return (Animal) factoryMap.get(action).newInstance();
    }
}

3 个答案:

答案 0 :(得分:6)

如果您使用的是Java 8,则可以像这样设置enum

enum AnimalFarm {
    Meow(Cat::new),
    Woof(Dog::new);

    public final Supplier<Animal> factory;
    private AnimalFarm(Supplier<Animal> factory) {
        this.factory = requireNonNull(factory);
    }
}

......

Animal dog = AnimalFarm.valueOf("Woof").factory.get();

您甚至可以使用enum工具Supplier<Animal>,然后执行AnimalFarm.valueOf("Meow").get();

答案 1 :(得分:0)

尝试这样的事情:

class MyFactory {
    private static final Map<String,Animal<?>> factoryMap =
        Collections.unmodifiableMap(new HashMap<String,Class>() {
            put("Meow", Cat.BASE_INSTANCE);
            put("Woof", Dog.BASE_INSTANCE);
    });

    public Animal createAnimal(String action) {
        return factoryMap.get(action).instance();
    }
}

interface Animal<SELF> {
    public SELF instance();
}

class Cat implements Animal<Cat> {
    public static final Cat BASE_INSTANCE = new Cat();
    public Cat() {}
    public Cat instance(){
        return new Cat();
    }
}
// And a similar Dog class

这根本不使用反射,ifswitch

答案 2 :(得分:0)

Java 8引入了一些不错的lambdas和功能接口,这使得这非常简单。它还避免了您在以前的Java版本中必须编写的许多丑陋的样板代码。有一点不能立即明确的是如何使用带有多个参数的构造函数来处理创建对象。大多数Java的功能接口都允许一个参数或根本不允许任何参数。在这种情况下,解决方案是实现您自己的功能接口。

想象一下,你的Animal类都有像这样的构造函数:

public Dog(String name, int age) {
    // constructor stuff
}

您可以在工厂类中创建一个名为Factory的函数接口,该接口具有3个参数。前两个参数是您要传递给构造函数的对象类型,第三个参数将是您要返回的对象。

public class AnimalFactory {

    private static final Map<String, Factory<String, Animal>> factoryMap;

    static {
        Map<String, Factory<String, Animal>> realMap = new HashMap<>();
        factoryMap = Collections.unmodifiableMap(realMap);

        realMap.put("MEOW", Cat::new);
        realMap.put("WOOF", Dog::new);
    }

    public static Animal createAnimal(String action) {
        return factoryMap.get(action).create(node);
    }

    @FunctionalInterface
    private interface Factory<T, R, S> {
        S create(T obj1, R obj2);
    } 
}

如果所有类都使用no-arg构造函数,那么您可以删除自定义界面并使用类似Supplier的内容。但其他一切应该或多或少保持不变。