Как управлять перекрестными ссылками в объектно-ориентированном дизайне? (пример шахмат) - PullRequest
1 голос
/ 27 февраля 2020

Я работаю над проектом Java, и я бы хотел действительно чистый «объектно-ориентированный» дизайн (насколько я могу ...).

Но я изо всех сил пытаюсь понять, как каждый объект должны ссылаться на остальные.

Давайте рассмотрим простой стандартный пример игры в шахматы:

  • Каждый игрок имеет заданное количество шахматных фигур.
  • Каждая фигура принадлежит 1 player

В моем приложении мне, вероятно, понадобится получить информацию в обоих направлениях :

  • Получите доступ к владельцу напрямую из фигуры
  • Получите доступ ко всем принадлежащим фигурам напрямую от игрока

Вот мои вопросы:

  1. Что бы быть лучшим дизайном? Каждый объект должен ссылаться на другой (ие)?
  2. Или X-ссылка просто всегда плоха? Должен ли я всегда получать доступ к объектам «в одностороннем порядке»?
  3. Может быть, мне следует создать еще один класс, который будет управлять отображением фигуры и игроков?

Мне не нравится решение X-ref, потому что оно в основном дублирует информацию и потенциально может вызвать несогласованность и большую перегрузку работы. Но можно ли этого избежать?

Я знаю, что эти вопросы немного размыты, но я не думаю, что смогу разобраться в одиночку! Пожалуйста, помогите!

Спасибо всем.

1 Ответ

1 голос
/ 27 февраля 2020

Это одна из тех ситуаций, когда выполнение OOP, насколько это возможно, приведет вас в тупик.

Может быть проще думать об этом так: у шахматной фигуры есть цвет, а не владелец.

Вы можете описать цвет, используя enum:

enum ChessColor {
  BLACK,
  WHITE
}

Я бы посоветовал не создавать сложную иерархию классов для типов фигур:

enum ChessPieceType {
  PAWN,
  KNIGHT,
  BISHOP,
  ROOK,
  KING,
  QUEEN
}

С их помощью определить простой тип шахматной фигуры легко (хотя Java немного многословно!) ...

public final class ChessPiece {
  public final ChessColor Color;
  public final ChessPieceType PieceType;

  public ChessPiece(final ChessColor color, final ChessPieceType pieceType) {
    this.color = color;
    this.pieceType = pieceType;
  }

  public boolean equals(final ChessPiece obj) {
    return this.pieceType == obj.pieceType && 
      this.color == obj.color;
  }

  @Override
  public boolean equals(final Object obj) {
    if (obj == this) {
      return true;
    }

    if (obj instanceof ChessPiece) {
      return equals((ChessPiece)obj);
    }

    return false;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;

    result = prime * result + color.hashCode();
    result = prime * result + pieceType.hashCode();

    return result;
  }
}

Но предположим, что вы хотите знать имя игрока, которому принадлежит фигура ? Я бы сказал, что это не свойство игры в шахматы, а свойство ситуации , в которой в нее играют.

public final class ChessMatch {
  public final Player playerWhite;
  public final Player playerBlack;
  public final Map<BoardPosition, Piece> board;

  // ...
}

Итак, чтобы ответить на ваш sepecifi c вопросов ...

Доступ к владельцу напрямую из части

Это не делает Смысл делать, так как владелец фигуры это не свойство шахмат, а только цвет. Вместо этого получите доступ к этому через ChessMatch (или любой другой объект).

Доступ ко всем принадлежащим фигурам напрямую от игрока

Это может быть реализовано как функция из BoardState к списку произведений. Например:

  public List<ChessPiece> fetchPiecesForColor(final Map<BoardPosition, ChessPiece> board, final ChessColor color) {
    final List<ChessPiece> results = new ArrayList<>();

    for (final Map.Entry<String, String> entry : board.entrySet()) {
      // ...
    }

    return results;
  }
...