Consider Chess as an example. Say, we have a lot of domain objects that are alike, in this case chess pieces. I have two proposes to implementing the behaviour of chess pieces. Both uses the following interface.
interface IPiece {
// ... shared behaviour
bool IsValidMove(int targetX, int targetY);
// ... more shared behaviour
}
Proposal 1: Functional Interfaces
Implement a standard implementation of a piece and use a functional interface.
interface IMoveValidator {
bool IsValidMove(int currentX, int currentY, int targetX, int targetY);
}
class Piece : IPiece {
private int _x, _y;
private IMoveValidator _moveValidator;
public Piece(int x, int y, IMoveValidator moveValidator) {
_x = x;
_y = y;
_moveValidator = moveValidator
}
// implement shared behaviour
public bool IsValidMove(int targetX, int targetY) {
_moveValidator(_x, _y, targetX, targetY);
}
}
class PawnMoveValidator {
bool IsValidMove(int currentX, int currentY, int targetX, int targetY) {
// do unique stuff
}
}
// implement KnightMoveValidator, QueenMoveValidator ...
Proposal 2: Decorator-like Implementations
Implement a base implementation of a piece and use a unique class for each piece.
class BasePiece {
private int _x, _y;
public BasePiece(int x, int y) {
_x = x;
_y = y;
}
// implement shared behaviour
}
class Pawn : IPiece {
private BasePiece _base;
public Pawn(int x, int y) {
_base = new BasePiece(x, y);
}
// delegate shared behaviour to BasePiece
public bool IsValidMove(int targetX, int targetY) {
// do unique stuff
}
}
// implement Knight, Queen ...
The second proposal could be implemented using shallow inheritance with an abstract base class, but I chose to favour the compositional implementation for the sake of comparison.
Question
Now the above two proposal can be used to implement a lot of different objects that are alike, for example Chess Pieces or Cards in a Trading Card Game. Sometimes there are a few alike objects, sometimes like in Chess there are 6, and sometimes like in Magic: The Gathering there are over 20.000 unique cards.
Should I favour one of the proposals over the other? What are the benefits and liability of each? Are there even better alternative proposals?