好的,雖然我試圖找到解釋問題的標題,但我可能需要對其進行擴展。將超類傳遞給需要子類的方法
最近我實現了一個用來控制磁帶庫的小程序。知道它必須適用於多種不同類型的磁帶庫,因此開發了以下設計。
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
}
這確實在SpecificTapeLibrary
意義,因爲編譯器必須顯式轉換超TapeDrive的亞型HPDrive這是由doSomethingWithDrive(HPDrive)預期的方法這將如何在一個很好的得到解決OOP方式?我最終沒有在doSomethingWithDrive方法中使用泛型並進行投射(如下所示:How to Pass a Child Class into a method requiring Super Class as parameter)。但這不可能是最佳解決方案。
在寫這篇文章時,另一個解決方案彈出到我的頭,這是更清潔。 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();
}
還有其他想法嗎?
爲什麼「類SpecificTapeLibrary實現了Tapelibrary」需要HPDrive而不是TapeDrive? –
efekctive
你的'DriveSelector'類沒有用處:你可以直接調用'inputList.get(0)'得到完全相同的結果。 –
@efekctive - 這個想法是,一個非抽象的(這是一個真實的世界磁帶庫)必須有一個非抽象的驅動器構建它。我可能會看到另一個缺陷,因爲這意味着磁帶庫總是有一種類型的驅動器構建到其中,但情況並非如此。 – user264235