多个对象引用共享对象(国际象棋游戏)

时间:2014-01-17 05:16:27

标签: oop design-patterns object-oriented-analysis

这个问题是关于设计以及持有对同一对象的引用的系统中许多对象的含义。我在其他项目中遇到过这个问题,但我认为它特别适用于我当前的项目。对于是否应该出于无法预料的原因避免任何一种设计,是否有任何指导?

这些例子涉及我正在研究的国际象棋程序。它们并不能代表我的实际代码,所以不需要对代码的质量进行评论,这些代码显然是为了简洁而牺牲的。

首次设计

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}},但在进行更改时,本身会更新当前的电路板。这样,所有部分都会引用最新的电路板。

1 个答案:

答案 0 :(得分:1)

不幸的是,这是一个高度自以为是的问题,这里没有完美的答案。但是,我相信很多人会同意,您在设计1之后创建设计2的见解总体上是强大的,从而使设计2在很多方面客观上更好。

你的头部很好,并且从Board定义和Piece中删除了Square引用。一个好的OOO设计原则是Objects应该只存储对概念上定义它们的引用。 BoardSquareBoardPosition?)没有定义该片段。

moves(...)方法很棘手。虽然Piece类似乎很好,但我认为Board类更好,但仍然不够。如果您打算创建一个完全准确的Chess实现,则必须设计En passantCastlingStalemate conditions,所有这些都不仅取决于当前Board状态,但以前的Board状态 - ChessGame的交易历史记录,如果您愿意的话。

我可以继续这里,但你应该为自己了解更多。所以,我会为你的消费留下一些更可疑的客观矿块:

  • 请务必警惕地使用Enums! PieceTypeColor是完美的候选人。枚举使您的代码更加精确和清晰,并且倾向于将令人讨厌的运行时错误转换为等效设计的简单编译错误。
  • 始终考虑到您的最终目标。如果您计划对这些类进行某种AI实验,请重新审视您使Board不可变的决定。这可能比您想要的快速分析更令人望而却步。
  • 与我之前的观点直接矛盾,在你知道至少需要两种不同的实现之前不要担心接口,并且你知道它们是什么。投机性抽象比短期限制更有害。