4

I'm trying to grok the Strategy pattern and came up with the following example:

  • I'd like to create new games based on chess except with pieces that move differently.
  • I also want to use the Strategy pattern to inject behaviors (how they can move) into the pieces.

But if we have Board, Piece, and MoveBehavior objects

  • Board -> Piece because a Board contains Pieces
  • Piece -> Board because a piece needs to pass in the Board as a param to
    • MoveBehavior which needs the Board to decide what moves are acceptable.

How can we get rid of this circular dependency? Also, isn't this a common problem in more realistic examples because behaviors need large enough state to make decisions? I think if the behavior is super simple it's not that big a deal to not use the Strategy pattern.

Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
petabyte
  • 1,487
  • 4
  • 15
  • 31

2 Answers2

3

It sounds like you can use a dependency injection framework to resolve all the object instances. You will need a configurable container if you want to use different combinations of types to instantiate. You could call the configurable container a strategy (as it selects all the pieces that come into play).

I would not make the board responsible for creating all the pieces and behaviors, but rather use a composer class (that uses dependency injection) for that.

This allows you (for example) to use behaviors for the board, or to create different board types as well.

See also this question and answer for some background on how dependency injection helps to obtain loose coupling.

Community
  • 1
  • 1
oɔɯǝɹ
  • 7,219
  • 7
  • 58
  • 69
1

I'd just use Board -> Piece -> MoveBehaviour.

The reason being is that the board contains the pieces and the pieces have their own move behaviour depending on what type they are.

MoveBehaviour tells the piece its allowed movements i.e. (example is C# because that is what I am familiar with)

public Move[] Moves
{
    get
    {
        return new Move[] { Move.Horizontal, Move.Vertical };
    }
}

The job of MoveBehaviour is not to see if the Piece can move to where it is requesting that is the board.

More easily explained in the below C# example:

public class Board
{
    public List<Piece> Pieces { get; set; }

    public bool CanMoveTo(Piece piece, Point location) { /*...*/ }
}

public class Piece : IMoveBehaviour
{
    public Move[] Moves { get; set; }
}

public interface IMoveBehaviour
{
    Move[] moves { get; set; }
}

And with methods in Board and Piece like RequestMove, Move, IsValidMove etc...

Essentially leave the responsibility of something to that something and do not move it around. MoveBehaviour is the behaviour of a Piece not the validation of the moves that is the Boards responsibility.

TheLethalCoder
  • 6,668
  • 6
  • 34
  • 69