0

我正在寻找一个干净的模式来解决以下问题:

我有几种类型的车辆(比如说 Car、Bike 和 Truck,所有这些类都扩展了抽象类 Vehicle)。每种类型的车辆都有几个特定的​​属性。

我在某处有一个车辆列表,我需要构建一个 GUI,使用户能够选择车辆并编辑其属性。我想要实现的结果是在左侧显示一个车辆列表(使用 JList),在右侧显示一个面板,其中包含编辑所选车辆所需的字段。

当列表仅包含一种类型的项目时,我知道该怎么做(我在左侧使用 Jlist,在右侧使用自定义 JPanel)。我为每个子类制作了一个自定义面板:CarPanel、BikePanel... 我的问题是所选车辆类型与相应面板之间的链接。虽然它会起作用,但我想避免这样的事情:

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

因为它对我来说似乎不是很容易维护。

我也想避免类似的事情,useThisPanel(selectedVehicle.getPanel())因为没有理由任何车辆类别都应该知道它的显示方式

我目前正在将我的代码转换为 MVC 模式,但在我看来,这还不足以解决我的问题。

我很确定我不是第一个面对这种情况的人,但我找不到任何答案或建议来管理这种情况。

4

1 回答 1

1

以 OO 方式解决此问题的常用方法是使用访问者模式

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
        }
    }
}

这是干净的一切,但它比一个简单的基于实例的解决方案更难理解。但它有一个优点:你不能忘记处理一个新的 Vehicle 类型:它会强制你实现抽象accept()方法,这会强制你向访问者接口添加另一个方法,这会强制你在每个访问者中实现它.

于 2013-05-13T17:39:59.037 回答