如何创建一个工厂,根据Java中的接口类型创建类?

How to create a factory, which creates classes according to interface type in Java?

我正在将 C# 项目迁移到 java。

在 C# 项目中,我有一个工厂 class 在类型和创建适当类型的委托之间保存字典。

我公开了一个泛型方法:

T Create<T>()

所以用户可以写:

var someObject = factory.Create<ISomeInterface>();

Create 方法代码类似于:

return (T)dictionary[typeof(T)]();

问题是,如何在 Java(版本 7)中做类似的事情?

非常感谢任何愿意提供帮助的人!

只要你想在IDictionary(或Java中的Map)中存储的类型没有类型参数,就可以了,你可以很容易地做一些类似于 C# 版本的事情。我决定将 Factory 的所有成员设为静态,但您可以使用实例方法 create 来做同样的事情。

public final class Factory {

    private Factory() {}

    private static interface InnerFactory<T> {
        T produce();
    }

    private static final class StringFactory implements InnerFactory<String> {
        @Override
        public String produce() {
            return "Random String " + Integer.toString(new Random().nextInt());   
        }
    }

    private static final class IntegerFactory implements InnerFactory<Integer> {
        @Override
        public Integer produce() {
            return new Random().nextInt();
        }
    }

    private static final Map<Class<?>, InnerFactory<?>> map = new HashMap<Class<?>, InnerFactory<?>>();

    private static <T> void put(Class<T> clazz, InnerFactory<T> innerFactory) {
        map.put(clazz, innerFactory);
    }

    static {
        put(String.class, new StringFactory());
        put(Integer.class, new IntegerFactory());
    }

    public static <T> T create(Class<T> clazz) {
        return clazz.cast(map.get(clazz).produce());
    }
}

您现在可以从其他地方呼叫 Factory.create(String.class)。如果您尝试在其中一种类型 T 具有类型参数的情况下执行相同的操作,这将在 Java 中分解。然后它变得更加复杂,因为由于类型擦除,像 List<String>.class 这样的表达式不是合法代码。

在 java 中,泛型类型参数信息在运行时不可用。所以在Create()方法中不可能从类型参数T中得到一个对应的Class对象。如果你想有这样一个工厂,你可以有一个类型提供者接口

public interface IProvider<T extends IBase> {
  T getInstance();
}

然后使用HashMap<Class<? extends IBase>, IFactory<? extends IBase>>维护工厂列表。所以你可以调用下面的方法来获取一个新的实例:

private HashMap<Class<? extends IBase>, IFactory<? extends IBase>> map;

@SuppressWarnings("unchecked")
public <T> T create(Class<T> type) {
    return (T) map.get(type).getInstance();
}

以使用create(Class<?>)方法为例,您可以这样调用:

ISomeInterface someObject = create(ISomeInterface.class);

请注意,您有责任确保 map 中的密钥类型和工厂的 return 类型匹配,否则将抛出 ClassCastException。

如果您不需要正在创建的类型扩展 IBase,只需省略代码片段中的所有 extends IBase

这是一个完整的例子:

package com.example.playground;

import java.util.HashMap;

public class TypeFactory {

    public interface IBase { }

    public interface IProvider <T extends IBase> {
        T getInstance();
    }

    private HashMap<Class<? extends IBase>, IProvider<? extends IBase>> registry =
            new HashMap<>();

    public <T extends IBase> void addProvider(Class<T> type, IProvider<T> provider) {
        registry.put(type, provider);
    }

    @SuppressWarnings("unchecked")
    public <T extends IBase> T create(Class<T> type) {
        return (T) registry.get(type).getInstance();
    }

    public static void main(String[] args) {
        TypeFactory factory = new TypeFactory();

        factory.addProvider(ISomeInterface.class, new IProvider<ISomeInterface>() {
            @Override
            public ISomeInterface getInstance() {
                return new ISomeInterface() {
                    @Override
                    public String toString() {
                        return "I'm a class that implements ISomeInterface";
                    }
                };
            }
        });

        ISomeInterface obj = factory.create(ISomeInterface.class);
        System.out.println(obj);
    }

}

interface ISomeInterface extends TypeFactory.IBase { }