好的,虽然我试图找到一个解释问题的标题,但我可能不得不对其进行扩展。
最近我实现了一个小程序,将用于控制磁带库。知道它必须使用多种不同类型的磁带库,因此开发了以下设计。
interface Tapelibrary<T extends TapeDrive> {
List<T> getListofDrives();
void doSomethingWithDrive(T d);
}
class SpecificTapeLibrary implements Tapelibrary<HPDrive> {
private List<HPDrive> driveList;
SpecificTapeLibrary() {
driveList.add(new HPDrive());
driveList.add(new HPDrive());
driveList.add(new HPDrive());
}
@Override
public List<HPDrive> getListofDrives() {
return driveList;
}
@Override
public void doSomethingWithDrive(HPDrive d) {
d.doSomethingHPspecific();
}
}
abstract class TapeDrive {
void doSomething() {
}
}
class HPDrive extends TapeDrive {
void doSomethingHPspecific() {
}
}
正确的磁带库由工厂根据命令行参数确定。
public static void main(String[] args) {
Tapelibrary<? extends TapeDrive> t = new TapeLibraryFabric().get();
List<? extends TapeDrive> listOfDrives = t.getListofDrives();
// the user selects a drive by using a small UI or something
TapeDrive selectedDrive = listOfDrives.get(0);
t.doSomethingWithDrive(selectedDrive); // compiler error
}
这确实有意义,因为编译器必须将父类型 TapeDrive 显式转换为子类型 HPDrive,这是SpecificTapeLibrary 中的 doSomethingWithDrive(HPDrive) 方法所期望的
这将如何以好的 oop 方式解决?我最终没有在 doSomethingWithDrive 方法中使用泛型和强制转换(如此处所建议的:如何将子类传递到需要超级类作为参数的方法中)。但这不可能是最佳解决方案。
在写这篇文章时,另一个解决方案突然出现在我的脑海中,它更清晰。DriveSelector 类封装了选择过程。
class DriveSelector {
<T> T selectDrive(List<T> inputList) {
// give the user an UI or something to select a drive
return inputList.get(0);
}
}
// the tape library then uses the selector
public void doSomethingWithSelectedDrive(DriveSelector selector) {
HPDrive t = selector.selectDrive(driveList);
t.doSomethingHPspecific();
}
还有其他想法吗?
在通用方法中完成所有工作:
static <T extends TapeDrive> void doStuff(Tapelibrary<T> t) {
List<T> listOfDrives = t.getListofDrives();
// the user selects a drive by using a small UI or something
T selectedDrive = listOfDrives.get(0);
t.doSomethingWithDrive(selectedDrive);
}
然后从您的主要方法调用它:
Tapelibrary<? extends TapeDrive> t = new TapeLibraryFabric().get();
doStuff(t);
它的工作方式是删除所有通配符 - 关于通配符的事情是编译器将每个通配符视为不同的,即使值是从单个通用实例派生的。通过像这样将东西放入泛型方法中,您可以让编译器知道所有的T
s 都是相同的类型——因此它可以知道调用是安全的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句