Domanda

This question refers to the Delegation design pattern found here.

I have a number of interfaces for my game engine representing various entities:

  • Player
  • Vehicle
  • Mesh
  • etc.

and each one of these can be rendered, so they implement the Renderable interface which contains the method render().

METHOD 1

Using delegation, an example looks like this:

public interface Vehicle {

    public void drive();

}

public class Car implements Vehicle {

    public Renderable renderable;

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

}

Whenever I want to render a car, I just call car.renderable.render();.

The problem with this method is that I cannot create a List and iterate through it.

METHOD 2

To solve this, I could have Vehicle extend Renderable:

public interface Vehicle extends Renderable {

    public void drive();

}

but the problem with this is that if I define Car, Bicycle, Truck, Tank, etc. each of these classes will have to fill in the code for render() (which will probably be identical).

Is there a way to maintain the benefits of extending Renderable in my Vehicle interface without being forced to define render() in all of my concrete classes implementing Vehicle?

È stato utile?

Soluzione

Regarding my comment,

Does each class that holds a Renderable have a public Renderable getRenderable() method? And if so, couldn't this be made into an interface allowing you to hold a collection of these beasts?

I was meaning something like this:

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

}

And nix that suggestion about implementing Iterable. I'm not sure what I was thinking.

Altri suggerimenti

Another approach might be to separate the concept of a Renderable object from its possible delegate renderer; in this way, you have the option of delegating to a common renderer or implementing the render() method right in a class, if your renderer code is specific to a single class.

Thinking further along, your renderer may need to query the instance of whatever entity it's trying to render -- imagine your Vehicle has methods to get its position on a map, and the renderer needs to get at those values in order to render it in the correct position; that's why the Renderer interface receives an instance of a 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.
    }
}

If the code for the render method will be identical among different classes, then do the following:

Introduce an abstract class called AbstractRenderable that implements Renderable. Then have the Car, Bicycle, etc. classes extend AbstractRenderable and implement Vehicle (or Player, etc.).

In the AbstractRenderable class, implement the render method. That way, all Cars, Bicycles, etc. rely on the "identical" render code. Plus, if the render code does differ on a Tank for example, you can simply override the render method.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top