当前位置: 代码迷 >> java >> OOP设计以两种方式避免对象的另一个对象
  详细解决方案

OOP设计以两种方式避免对象的另一个对象

热度:81   发布时间:2023-07-17 20:28:00.0

我正在写一个Java国际象棋游戏,我正在尝试整理设计。 这是我到目前为止的课程:

游戏:由2个玩家对象和一个棋盘对象组成

玩家:

板:由2d阵列(8×8)的Square对象组成,每个对象可能/可能没有一块

King,Queen,Rook,Bishop,Knight,Pawn:

Piece:上述部分的超类,共享功能在这里

这就是我不喜欢的内容:我的Square类中有一个名为“board”的字段,因此我可以引用给定方块所属的板。 我不喜欢这种设计,因为它会导致克隆问题。

所以我想在片段类中重写一些功能而不进行这种回溯。 对于一个能够访问每个方块的板子来说非常棒,但是我不想为Square类提供getBoard()函数。

这是我需要重写的函数示例:

public Square getSquareOneMoveAway(Square start, int heightChange, int widthChange) {

    Square candidateSquare = start.getBoard().getNearbySquare(start, heightChange, widthChange);

    if (candidateSquare != null) {
        if (candidateSquare.isEmpty()) {
            return candidateSquare;
        } else if (! candidateSquare.getPiece().getColor().equals(start.getPiece().getColor())) {
            return candidateSquare;
        }
        else {
            return null;
        }
    }
    else {
        return null;
    }
}

请注意,在我的Player类中,我有以下方法:

canMovePiece(Square start,Square end,Board board),movePiece(Square start,Square end,Board board)等

我是否应该将此方法移入Board类中,这样我就可以访问板对象而无需从Square转到板上?

任何想法都非常感激,bclayman

在我看来,你过度设计了这个问题。 用另一个类代表电路板的方块真的有什么好处吗? 如果不是(我不这么认为)我只是摆脱了Square类。

class Board {
    public static final int MAX_ROWS = 8;
    public static final int MAX_COLS = 8;

    private Piece[][] squares;

    public Board() {
        squares = new Piece[ MAX_ROWS ][ MAX_COLS ];
    }

    // ...
}

不过,我有一个Position类,它有一对和一列。

希望这可以帮助。

以下ChessBoard定义用于存储碎片,存储它们的位置,并使用该信息来确定给定移动是否有效。

class ChessBoard implements Board {
    Piece[][] pieces; // null if vacant at that position

    @Override
    public boolean isValidMove(Player player, Square start, Square end) {
        Piece pieceStart = pieces[start.row][start.col];
        Piece pieceEnd = pieces[end.row][end.col];

        return (
            pieceStart != null &&
            pieceStart.getColor() == player.getColor() &&
            pieceStart.isValidTransition(start, end) &&
            (pieceEnd == null || pieceStart.canDefeat(pieceEnd))
        );
    }
}

请注意,移动是否有效的逻辑被封装在正在移动的部分中。

class Pawn implements Piece {

    @Override
    public boolean isValidTransition(Square start, Square end) {
        int dH = end.col - start.col;
        int dW = end.row - start.row;
        // return if is valid transition for a pawn in terms of dH and dW
    }

    @Override
    public boolean canDefeat(Piece otherPiece) { 
        return (
            this.getColor() != otherPiece.getColor() &&
            this.getStrength() > otherPiece.getStrength()
        );
    }

    @Override
    public int getStrength() { ... }

    @Override
    public Color getColor() { ... }
}

square类只是一个包含行和列的简单2元组。

class Square {
    int row, col;
}

我是一个实用主义者,所以我不会把它作为课程,只是枚举。 所以:

enum Pieces 
{
   Pawn,
   Rook,
   Knight
   // etc
};

然后我创建一个名为'Rule'的接口,如下所示:

interface Rule
{
   void addRule(Pieces p);
};

其中,通过让一个类实现规则,我可以决定单元在游戏中如何相互作用(或者最好在它上面)。 这个类将是PawnRule,QueenRule等。这样做,可以为游戏添加尽可能多的规则并使用它们。 这不仅有利于可扩展性,而且为游戏本身带来了可行的基础。

class PawnRule implements Rule
{
    private boolean pFirstMove = true;
    // etc
    void addRule(Pieces p)
    {
        if (Square.hasSpace(Space.FRONT) * 2 && pFirstMove)
        {
            // where renderer holds 2D/3D data pertaining to the piece
            rendrerer.getModel("Pawn").moveByTwo(); // somehow
        }
    }
}

在设计方面,还有很多需要考虑的因素; 并且可能是枚举不是你想要的。 我们也不知道游戏是基于文本的,2D还是3D。 一般来说,如果它是基于文本的,那么实现这些东西会更容易,但是当它是3D时更加复杂。 我建议您绘制一个类图,甚至是通信图,这样您就可以知道国际象棋游戏中的类/枚举/接口如何相互作用。

  相关解决方案