Reputation: 13
I'm programming a board game in C# where the two most important classes are Piece
and Square
. Typically every instance of Piece
has a Square
(as a property) and every instance of Square
may have a Piece
(also as a property) or may be empty.
I placed code in the set methods of Square.Piece
and Piece.Square
to ensure that this relationship was maintained (e.g. when a piece is moved from one square to another) and to avoid the obvious danger of the linked properties calling each other's set methods in an endless loop.
But when a piece
is removed from the board and its square
set to 'null' I seem to have too many if statements to avoid null exceptions and what seemed a very simple pattern conceptually becomes far too complex and error-prone in practice.
I'm wondering whether my whole approach is wrong. Should a piece
have a square
as a property when Square
also has Piece
as a property? Have I in fact started coding an anti-pattern? A Piece
's Square
may be null on creation, and a Square
's Piece
is frequently null (representing empty). Should I use another way to represent empty Squares and Pieces which are not on the board?
I'm assuming there are preferred, robust solutions to the more general case of when one class is linked to another in a two-way relationship such as this.
Many thanks for any ideas.
Upvotes: 1
Views: 276
Reputation: 97656
It seems to me that you're overthinking the process of removing a Piece
from the Board
.
The game is going to be centered on the Board
class. Once you remove a Piece
from the Board
, that piece is gone; you're not going to do anything with it anymore. You won't be calling any of its methods or anything. That object is now dead -- unreachable. So there's not actually any reason to change the Piece
's state to null out its Board
reference.
This is indeed a very common pattern, and the usual practice is to just let it go. Once nobody references the Piece
anymore, you're done; it no longer matters that the Piece
still happens to reference the Board
. Let it keep its reference; it won't cause any harm (since nobody will be doing anything with that Piece
anymore), and it'll be garbage collected soon anyway.
Upvotes: 1
Reputation: 24780
Use an higher level abstraction, with methods like
move(piece, originalSquare, destinationSqueare)
place(piece, square)
remove(piece)
promote(originalPiece, finalPiece)
these methods will use your basic methods from Piece
and Square
, and will be the ones used by your main logic
Upvotes: 2