有没有办法在不失去Java可替代性的情况下使用委托设计模式?

时间:2013-01-14 22:17:26

标签: java composition aggregation liskov-substitution-principle

此问题涉及找到的{strong>委派设计模式here

我的游戏引擎有许多界面代表各种实体:

  • 播放器
  • 车辆

并且可以渲染其中的每一个,因此它们实现了包含方法render()的Renderable接口。

方法1

使用委托,示例如下:

public interface Vehicle {

    public void drive();

}

public class Car implements Vehicle {

    public Renderable renderable;

    @Override
    public void drive() { // ... }

}

每当我想要开车时,我只需拨打car.renderable.render();

这种方法的问题在于我无法创建List并迭代它。

方法2

要解决这个问题,我可以让Vehicle extend Renderable:

public interface Vehicle extends Renderable {

    public void drive();

}

但问题是,如果我定义Car,Bicycle,Truck,Tank等,这些类中的每一个都必须填写render()的代码(可能是相同的)。

有没有办法在我的Vehicle界面中保持扩展Renderable的好处而不必强制在我实现Vehicle的所有具体类中定义render()?

3 个答案:

答案 0 :(得分:2)

关于我的评论,

  

拥有Renderable的每个类都有一个公共Renderable getRenderable()方法吗?如果是这样的话,难道不能将它变成一个允许你拥有这些野兽集合的界面吗?

我的意思是这样的:

interface Renderable {
   void render();
}

interface RenderDelegator {
   Renderable getRenderable();
   void setRenderable(Renderable renderable);
}

abstract class Vehicle implements RenderDelegator {
   private Renderable renderable;

   @Override
   public Renderable getRenderable() {
      return renderable;
   }

   @Override
   public void setRenderable(Renderable renderable) {
      this.renderable = renderable;
   }

   public abstract void drive();
}

class Car extends Vehicle {
   @Override
   public void drive() {
      // TODO finish!
   }

}

并且nix提出了关于实现Iterable的建议。我不确定我在想什么。

答案 1 :(得分:1)

另一种方法可能是将Renderable对象的概念与其可能的委托渲染器分开;通过这种方式,如果渲染器代码特定于单个类,则可以选择委托给公共渲染器或在类中实现render()方法。

进一步思考,你的渲染器可能需要查询它试图渲染的任何实体的实例 - 想象你的Vehicle有方法来获取它在地图上的位置,并且渲染器需要获取这些值以便渲染它处于正确的位置;这就是Renderer接口接收Renderable实例的原因。

interface Renderable {
    void render();
}

interface Vehicle extends Renderable {
    void drive();
}

interface Renderer<T extends Renderable> {
    void render(T renderable);
}

public class VehicleRenderer implements Renderer<Vehicle> {
    public void Render(Vehicle renderable) {
        // TODO: Render a Vehicle.
    }
}

public class Car implements Vehicle {
    private Renderer<Vehicle> renderer;

    public void setRenderer(Renderer<Vehicle> renderer) {
        this.renderer = renderer;
    }

    public void render() {
        renderer.render(this);
    }

    public void drive() {
        // TODO: Drive the car.
    }
}

答案 2 :(得分:0)

如果render方法的代码在不同的类之间是相同的,请执行以下操作:

引入一个名为AbstractRenderable的抽象类,它实现Renderable。然后让CarBicycle等类扩展AbstractRenderable并实施Vehicle(或Player等)。

AbstractRenderable课程中,实施render方法。这样,所有汽车,自行车等都依赖于“相同”的渲染代码。另外,如果渲染代码在Tank上确实不同,您可以简单地覆盖render方法。