2013-05-13 70 views
0

我在尋找一個乾淨的模式來解決以下問題:創建通用GUI的幾個子類

我有幾個類型的車輛(比方說汽車,自行車和汽車,所有這些類擴展抽象類的交通工具) 。每種類型的車輛都有幾個特定的​​屬性。

我有一個地方的車輛列表,我需要建立一個GUI,使用戶能夠選擇一輛車,並編輯它的屬性。我想實現的結果是在左側顯示車輛列表(使用JList),右側顯示包含編輯所選車輛所需字段的面板。

我知道如何做到這一點,當列表只包含一種類型的項目(我使用左邊的Jlist和右邊的自定義JPanel)。我爲每個子類製作了一個自定義面板:CarPanel,BikePanel ... 我的問題是所選車輛類型與相應面板之間的鏈接。雖然它會工作,我想避免這樣的事情:

if (selectedVehicle instanceof Car) { 
    useThisPanel(new CarPanel((Car)selectedVehicle)); 
} ... 

因爲它不似乎很容易維護我。

我也想避免像useThisPanel(selectedVehicle.getPanel())因爲沒有任何理由車輛類別應該瞭解它顯示

我目前正在對我的代碼切換到MVC模式的方式什麼,但似乎對我來說這不足以解決我的問題。

我很確定我不是第一個面對這個問題的人,但我找不到任何答案或建議來管理這種情況。

+0

使用反射來獲取字段名稱和類型。 – 2013-05-13 16:05:04

回答

1

在一個面向對象的方式解決這個問題的常用方法是使用visitor pattern

public interface VehicleVisitor<T> { 
    T visitCar(Car car); 
    T visitTruck(Truck truck); 
    T visitBike(Bike bike); 
} 

public abstract class Vehicle { 
    public abstract <T> T accept(VehicleVisitor<T> visitor); 
} 

public class Car extends Vehicle { 
    @Override 
    public <T> T accept(VehicleVisitor<T> visitor) { 
     return visitor.visitCar(this); 
    } 
} 

// same for Bike and Truck 

最後

public class SomeClass { 
    private JPanel createPanelFor(Vehicle vehicle) { 
     return vehicle.accept(new VehicleVisitor<JPanel>() { 
      @Override 
      public JPanel visitCar(Car car) { 
       return new CarPanel(car); 
      } 
      // same for Truck and Bike 
     } 
    } 
} 

這是乾淨的一切,但它更困難一點理解比簡單的基於instanceof的解決方案。但它有一個優點:你不能忘記處理一個新的Vehicle類型:它會迫使你實現抽象accept()方法,這將迫使你添加另一個方法到Visitor接口,這將迫使你在每一個方法中實現它遊客。

+0

該死的,我應該自己找到它,這個模式在我的書中!它完美地回答了這個問題。謝謝。 – Zerdligham 2013-05-13 18:06:13

+0

非常好的教訓+1 – mKorbel 2013-05-13 18:23:46