如何创建一个工厂,根据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 { }
我正在将 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 { }