2013-05-13 67 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