Java – Clean OOP way of mapping an object to its presenter

designjavaobject-oriented

I am creating a board game (such as chess) in Java, where each piece is its own type (like Pawn, Rook etc.). For the GUI part of the application I need an image for each of these pieces. Since doing thinks like

rook.image();

violates separation of UI and business logic, I will create a different presenter for each piece and then map the piece types to their corresponding presenters like

private HashMap<Class<Piece>, PiecePresenter> presenters = ...

public Image getImage(Piece piece) {
  return presenters.get(piece.getClass()).image();
}

So far so good. However, I sense a prudent OOP guru would frown upon calling a getClass() method and would suggest using a visitor for example like this:

class Rook extends Piece {
  @Override 
  public <T> T accept(PieceVisitor<T> visitor) {
    return visitor.visitRook(this);
  }
}

class ImageVisitor implements PieceVisitor<Image> {
  @Override  
  public Image visitRook(Rook rook) {
    return rookImage;
  } 
}

I like this solution (thank you, guru), but it has one significant drawback. Every time a new piece type is added to the application the PieceVisitor needs to be updated with a new method. I would like to use my system as a board game framework where new pieces could be added through a simple process where the user of the framework would only provide implementation of both the piece and its presenter, and simply plug it into the framework. My question: is there a clean OOP solution without instanceof, getClass() etc. which would allow for this kind of extensibility?

Best Answer

is there a clean OOP solution without instanceof, getClass() etc. which would allow for this kind of extensibility?

Yes there is.

Let me ask you this:

In your current examples you're finding ways to map piece types to images. How does this solve the problem of a piece being moved?

A more powerful technique than asking about type is to follow Tell, don't ask. What if each piece took a PiecePresenter interface and it looked like this:

class PiecePresenter implements PieceOutput {

  BoardPresenter board;
  Image pieceImage;

  @Override
  PiecePresenter(BoardPresenter board, Image image) {
    public void display(int rank, int file) {
      board.display(pieceImage, rank, file);
    } 
  }
}

The construction would look something like this:

rookWhiteImage = new Image("Rook-White.png");
PieceOutput rookWhiteOutPort = new PiecePresenter(boardPresenter, rookWhiteImage);
PieceInput rookWhiteInPort = new Rook(rookWhiteOutPort);
board[0, 0] = rookWhiteInPort;

Use would look something like:

board[rank, file].display(rank, file);

The idea here is to avoid taking responsibility for doing anything that other things are responsible for by not asking about it nor making decisions based on it. Instead hold a reference to something that knows what to do about something and tell it to do something about what you know.

This allows for polymorphism. You don't CARE what you're talking to. You don't care what it has to say. You just care that it can do what you need done.

A good diagram that keeps these in separate layers, follows tell-don't-ask, and shows how to not couple layer to layer unjustly is this:

enter image description here

It adds a use case layer we haven't used here (and can certainly add) but we are following the same pattern you see in the lower right corner.

You'll also notice that Presenter doesn't use inheritance. It uses composition. Inheritance should be a last resort way to get polymorphism. I prefer designs that favor using composition and delegation. It's a bit more keyboard typing but it's a lot more power.