我正在尝试使用适配器模式构建SDK。这是我到目前为止所得到的:
interface Adapter<T> {
void doWork(WorkUnit<T> unit);
Class<T> getT();
}
class WorkUnit<T> {
public int getId() { ... }
public T getExtras() { ... }
}
class OldWorkUnit {
public <T> void setExtra(T data) { /* Store data in Map<Class, Object> */ }
public <T> WorkUnit<T> toNewWorkUnit(Adapter<T> adapter) { /* Map.get(adapter.getT()) */ }
}
那里有很多泛型,但我在编译时无法知道T,并且可能有多个适配器,都有不同类型的T.这是为了暴露给第三方,所以我也在接口实现中需要尽可能少的实现,它必须是一个接口(没有抽象类)。
现在我想接受这个并用WorkUnit调用doWork。我在代码中的第一次传递看起来像这样:
class FooAdapter implements Adapter<FooWorkUnit> {
...
}
OldWorkUnit w = new OldWorkUnit();
w.setExtra(new FooWorkUnit());
Adapter<?> a = new FooAdapter();
WorkUnit<?> unit = w.toNewWorkUnit(a);
a.doWork(unit);
哦,哦,不编译:
The method doWork(WorkUnit<capture#2-of ?>) in the type Adapter<capture#2-of ?>
is not applicable for the arguments (WorkUnit<capture#4-of ?>)
我知道WorkUnit泛型参数与Adapter.doWork()泛型参数的类型相同,但不知道类型我无法正确地转换它。
那么有没有办法解决这个问题呢?
答案 0 :(得分:1)
为什么在这里通配模板类?:
Adapter<?> a = new FooAdapter();
WorkUnit<?> unit = w.toNewWorkUnit(a);
如果你这样做:
Adapter<FooWorkUnit> a = new FooAdapter();
WorkUnit<FooWorkUnit> unit = w.toNewWorkUnit(a);
这不能保留您的需求吗?
现在编译器知道FooWorkUnit
是共同点,可以这么说。
编辑:关于运行时可变性的确定点。如何强力键入执行工作的方法,以便消除通配符,但仍然是一致的:
@SuppressWarnings("unchecked")
public <X> void prepareArgsAndDoTheWork() {
OldWorkUnit w = new OldWorkUnit();
w.setExtra(new FooWorkUnit());
Adapter<X> a = (Adapter<X>) ... ; // Obtain the Adapter by reflection etc
WorkUnit<X> unit = w.toNewWorkUnit(a);
a.doWork(unit);
}