这个问题是关于设计以及持有对同一对象的引用的系统中许多对象的含义。我在其他项目中遇到过这个问题,但我认为它特别适用于我当前的项目。对于是否应该出于无法预料的原因避免任何一种设计,是否有任何指导?
这些例子涉及我正在研究的国际象棋程序。它们并不能代表我的实际代码,所以不需要对代码的质量进行评论,这些代码显然是为了简洁而牺牲的。
public class Piece
{
private Board board;
private PieceType type;
private Color color;
private Square location;
public Piece(PieceType type, Color color, Board board, Square square)
{
// assignments to members
}
public Move[] moves()
{
type.moves(board, location);
}
}
public final class Board // Board is immutable
{
// Would have to manage pieces with duplicate squares
private List<Piece> pieces;
public Board placePiece(PieceType type, Color color, Square square)
{
Piece p = new Piece(type, color, this, square);
pieces.add(piece);
}
public Move[] moves(Square fromLocation)
{
Piece p = pieces.get(fromLocation);
return p.moves();
}
}
我放弃了这种设计,其中每个Piece
在构造时都引用了Board
。
我认为Piece
在他们被要求确定他们的可用动作时,只需要Board
当前状态时保持这个参考是很尴尬的。我倾向于在构造函数中注入依赖项而不是方法,因为它从客户端删除了上下文。但是,我不喜欢这种设计,特别是每次电路板更换时必须使用新电路板更新这些部件。由于Board
是不可变的,Pieces
将保持对具有过期状态的Board
的引用。创建一个新的Board
也需要创建所有新的Piece
,这似乎是很多不必要的计算;特别是考虑到他们中的许多人甚至不会在给定的回合中调用moves
,即甚至不会利用最新的Board
。
最好将位置信息存储在Board
中,并将电路板和位置传递到Piece
的{{1}}方法吗?
moves
我能想到使用第一个设计的另一种方法是不在public class Piece
{
private PieceType type;
private Color color;
public Piece(PieceType type, Color color)
{
// assignments to members
}
// Can pass in
public Move[] moves(Board board, Square location)
{
type.moves(board, location);
}
}
public class Board
{
// No duplicate squares allowed
private Map<Square, Piece> pieces;
public Board placePiece(PieceType type, Color color, Square square)
{
Piece p = new Piece(type, color);
pieces.put(square, piece);
}
public Move[] moves(Square fromLocation)
{
Piece p = pieces.get(fromLocation);
return p.moves(this, fromLocation);
}
}
的构造函数中传递对Board
的引用,而是传递一个匹配{Piece
的代理。 1}},但在进行更改时,本身会更新当前的电路板。这样,所有部分都会引用最新的电路板。
答案 0 :(得分:1)
不幸的是,这是一个高度自以为是的问题,这里没有完美的答案。但是,我相信很多人会同意,您在设计1之后创建设计2的见解总体上是强大的,从而使设计2在很多方面客观上更好。
你的头部很好,并且从Board
定义和Piece
中删除了Square
引用。一个好的OOO设计原则是Objects应该只存储对概念上定义它们的引用。 Board
和Square
(BoardPosition
?)没有定义该片段。
moves(...)
方法很棘手。虽然Piece
类似乎很好,但我认为Board
类更好,但仍然不够。如果您打算创建一个完全准确的Chess实现,则必须设计En passant,Castling和Stalemate conditions,所有这些都不仅取决于当前Board
状态,但以前的Board
状态 - ChessGame
的交易历史记录,如果您愿意的话。
我可以继续这里,但你应该为自己了解更多。所以,我会为你的消费留下一些更可疑的客观矿块:
PieceType
和Color
是完美的候选人。枚举使您的代码更加精确和清晰,并且倾向于将令人讨厌的运行时错误转换为等效设计的简单编译错误。Board
不可变的决定。这可能比您想要的快速分析更令人望而却步。