我有以下界面
public interface Splitter<T, V> {
V[] split(T arg);
}
以下是我用来获取Splitter实现的工厂方法实现。
工厂方法实施
public static <T, V> Splitter<T, V> getSplitter(Class<T> key1, Class<V> key2) {
if (key1 == Company.class && key2 == Department.class)
return (Splitter<T, V>) new CompanySplitterImpl();
// more cases
}
以下是我在客户端的电话,其编译很好
Splitter<Company, Department> split = getSplitter(Company.class, Department.class);
我想避免客户端代码与实现紧密耦合。有没有办法避免硬编码类型参数,即避免在被叫方使用公司和部门(Splitter<Company, Department>
)并使用某些变量?有没有办法从一些外部属性文件中加载它们?
仅供参考:我不确定它在Java中的可行性吗?
答案 0 :(得分:1)
你可以做的一件事是你让工厂对具体实现一无所知,而是让自己注册(或包含一个预定义的列表)并询问每个实现是否可以处理类型。例如,给定一个预定义的列表,如上例所示:
public class SplitterFactory {
private Set<Splitter> splitters = new HashSet<>() {{
add(new CompanySplitterImpl());
}};
public static <T, V> Splitter<T, V> getSplitter(Class<T> key1, Class<V> key2)
{
for (Splitter splitter : splitters) {
if (splitter.canAccept(key1, key2)) {
return splitter;
}
// no matched splitter
}
}
显然,这是一个非常天真的解决方案,您可以更有效地实现查找。如果在编译时不知道类型,那么您也可以在工厂中使用注册机制在运行时包含新的类型。因为Splitter现在负责报告它可以处理的类型,所以它是完全可扩展的。
答案 1 :(得分:1)
你可以制作一个简单的地图类,你可以将它们列出来:
public final class SplitterMap {
private final List<SplitterType<?, ?>> list = new ArrayList<>();
private class SplitterType<T, V> {
private final Class<T> key1;
private final Class<V> key2;
private final Class<? extends Splitter<T, V>> clazz;
private SplitterType(Class<?> key1, Class<?> key2, Class<? extends Splitter<T, V> clazz) {
this.key1 = key1;
this.key2 = key2;
this.clazz = clazz;
}
private boolean matches(Class<?> key1, Class<?> key2) {
return this.key1 == key1 && this.key2 == key2;
}
}
public <T, V> void put(Class<T> key1, Class<V> key2, Class<? extends Splitter<T, V> clazz) {
list.add(new SplitterType<T, V>(key1, key2, clazz));
}
public <T, V> Splitter<T, V> get(Class<T> key1, Class<V> key2) {
for (SplitterType<?, ?> type : list) {
if (type.matches(key1, key2)) {
try {
return ((SplitterType<T, V>) type).clazz.newInstance();
} catch (Exception e) {
}
}
}
return null; // not found
}
}
然后你可以这样做:
SplitterMap map = new SplitterMap();
map.put(Company.class, Department.class, CompanySplitterImpl.class);
Splitter<Company, Department> splitter = map.get(Company.class, Department.class);
答案 2 :(得分:0)
不是一个好方法,但有一种方式:
String companyClass = "Company";
String departmentClass = "Department";
Splitter split = getSplitter(Class.forName(companyClass), Class.forName(departmentClass));//raw splitter
System.out.println(split.split(new Company()));//you could use reflection here to create instance from companyClass String.
答案 3 :(得分:0)
首先我假设你想要像
这样的东西Splitter<Company, Department> s = Splitters.getSplitter()
由于
,没有反思是不可能的其次你滥用FactoryMethod模式。哪个应该更像这样:
interface Splitter<T, V> {
V[] split(T arg);
}
interface SplitterFactory {
<T, V> Splitter<T, V> getSplitter();
}
class CompanySplitterFactory implements SplitterFactory {
@Override
public Splitter<Company, Department> getSplitter() {
return new CompanySplitterImpl();
}
}