0

我在尝试完成需要使用策略和复合模式的实践时遇到了真正的麻烦。我正在尝试创建一个车辆集合,这些车辆可以根据它们所在的表面具有不同的行为。但是,这些车辆在表面上可能有不止一种行为 - 例如,如果天气条件设置为下雪和下雨,它们可能同时进行雪地行驶和雨天行驶。

我有一个名为 AbstractVehicle 的类,它有两个具体的子类,Car 和 Boat。

然后我有一个名为 IBehaviour 的界面。实现此接口的是两个抽象类,称为 LandBehaviour 和 WaterBehaviour(它们是复合模式的顶层)。它们中的每一个都有一个子类的集合。只关注 LandBehaviour,它的子类是 SnowBehaviour、StandardBehaviour 和其他一些,包括 LandAssembly。

我的想法是我将把复合材料的上层代码放在 LandBehaviour 中。然后,每个具体的子类将具有复合的添加、删除和列出部分的空实现,其中 LandAssembly 类包含实际将各种行为组合在一起所需的代码。

这是为了产生这样的结果,例如,一辆汽车可以同时具有 StandardBehaviour 和 SnowBehaviour。

我没有发布大量代码(而且有很多),而是希望对我正在尝试实现的基本结构提供一些反馈。我现在遇到了一些错误,例如空指针异常,而不是花很长时间尝试修复它们,我想了解项目的布局是否一开始就正确。

编辑:添加代码 - 生成空指针异常

这是我的 AbstractVehicle 类:

public AbstractVehicle (IBehaviour behaviourIn) {
    behaviour = behaviourIn;
}

public void setBehaviour(IBehaviour ib) {
    behaviour = ib;
}

public IBehaviour getBehaviour() {
    return behaviour;
}

public void move() {
    behaviour.ensureCorrectBehaviour();
}

汽车子类:

public Car () {
    super(new StandardBehaviour());
}

IBehaviour 界面:

public interface IBehaviour {
    public void ensureCorrectBehaviour();
}

LandBehaviour 抽象类:

public void ensureCorrectBehaviour() {
}

public ILandBehaviour () {
}

private ILandBehaviour landBehaviour;

public ILandBehaviour (ILandBehaviour landBehaviour) {
    this.landBehaviour = landBehaviour;
}

public ILandBehaviour getBehaviour() {
    return landBehaviour;
}

public abstract void addBehaviour(ILandBehaviour behaviour);
public abstract void removeBehaviour(ILandBehaviour behaviour);
public abstract ILandBehaviour[] getBehaviours();

具体行为子类 (RacingBehaviour) 的示例:

public RacingBehaviour(ILandBehaviour landBehaviour) {
    super(landBehaviour);
}

public RacingBehaviour() {}

@Override
public void ensureCorrectBehaviour() {
    System.out.println("Vehicle is racing.");
}

public void addBehaviour(ILandBehaviour behaviour) {}
public void removeBehaviour(ILandBehaviour behaviour) {}
public ILandBehaviour[] getBehaviours() {
    return null;
}

最后是 LandAssembly 类:

public class LandAssembly extends ILandBehaviour {

private List<ILandBehaviour> behaviours;

public LandAssembly(ILandBehaviour landBehaviour) {
    super(landBehaviour);
    behaviours = new ArrayList<ILandBehaviour>();
}

public LandAssembly() {}

public void addBehaviour(ILandBehaviour behaviour) {
    behaviours.add(behaviour);
}

public void removeBehaviour(ILandBehaviour behaviour) {
    behaviours.remove(behaviour);
}

public ILandBehaviour[] getBehaviours() {
    return behaviours.toArray(new ILandBehaviour[behaviours.size()]);
}   
}

我正在使用这个跑步者:

    AbstractVehicle aCar = new Car(120);
    aCar.move();

    ILandBehaviour snow = new SnowBehaviour();
    ILandBehaviour racing = new RacingBehaviour();
    ILandBehaviour as = new LandAssembly();
    as.addBehaviour(snow);
    as.addBehaviour(racing);

在我实施复合材料之前,一切都很好。我能够使用客户端创建一辆新车,调用它的 move() 方法,然后改变它的行为,再次调用 move() 并查看差异。然而,我知道我现在有点将 ensureCorrectBehaviour() 方法留在复合模式的实现中,这显然是错误的。我也知道,在这样做之后, Car 构造函数的“新”部分不起作用——我必须为每个行为添加一个空构造函数。

我可以在我创建的代码中看到明显的问题,我只是不太明白如何解决它们。

4

1 回答 1

0

如果您关心设计模式,类图将非常有用。您有许多特征,并且将这些特征分组为更高级别的抽象(例如雪/土地/水/等)。但是您的车辆只接受一种行为。车辆是否需要具备多种功能?(当然,正如你提到的那样)。

您可能会考虑在您的类中使用具体定义的策略,其中每个策略的实现可能会有所不同。

public abstract class Bird
{
    protected BirdCallStrategy callStrat;
    protected FlyStrategy flyStrat;
}

public class Duck
{
    public Duck()
    {
        callStrat = new QuackStrategy();
        flyStrategy = new FlySouthForWinterStrategy(TimeOfYear);
    }
}

public class Chicken
{
    public Chicken()
    {
        callStrat = new CluckStrategy();
        flyStrat = new NoFlyStrategy();
    }
}

如果您的策略有不同的抽象,这很有效。在这种情况下FlyingBirdCalling彼此无关,但允许它们在运行时因实现而异(嘎嘎声、啁啾或飞行、不飞行等)

但是,如果您想在不进行子类型化的情况下动态创建不同的实例,您可能需要研究装饰器模式装饰器模式允许您在运行时将“功能”的任意组合应用于实例。

因此,您最终可能会得到一个实例化的对象,例如:

Window decoratedWindow = new HorizontalScrollBarDecorator (
                new VerticalScrollBarDecorator(new SimpleWindow()));
于 2013-03-19T23:53:17.770 回答