Объектно-ориентированное программирование - практика двухсторонней композиции? - PullRequest
0 голосов
/ 14 марта 2019

Мой вопрос касается аспекта «композиции» в объектно-ориентированном программировании.Я программирую на Java, но это может относиться к любому языку.

Моя проблема заключается в двухсторонней композиции.Я слышал, что композиция подразумевает отношения "есть".Представьте, что вы строите игру в шашки, в моем случае у меня был бы класс "Board" для генерации доски, поля HAS и квадраты могут иметь фигуры (класс Piece) или быть пустыми.Композиция (исходя из моего понимания) сказала бы, что наша доска должна иметь массив квадратных объектов внутри, а квадратные объекты должны иметь поле фигуры внутри.

public class Board {

    private List<Square>;

    ... (generating board, other functions/fields)

}

public class Square {

    private Piece piece;

    ... (other functions/fields)

}

public class Piece {

    ... (functions/fields)

}

Так я понимаю композицию.Моя проблема, да, у доски есть квадраты и части, но разве не имеет смысла, что у части есть также доска?Если вы создали метод перемещения в классе фигур, вам не нужно было бы получить доступ к доске и ее квадратам?Примерно так:

public class Piece {

    private Board board;

    ... (constructor/functions/fields)

    public void move(int x, int y) {

        if (this.board.getSquare(x, y).isEmpty())
            System.out.println("Piece moves to (x, y)");

        ... (etc.)
    }
}

Это считается хорошей практикой проектирования или есть лучший способ реализовать это?

Ответы [ 2 ]

2 голосов
/ 14 марта 2019

Здесь действительно есть два вопроса. Двусторонняя композиция - или, вообще говоря, двусторонняя ассоциация - сама по себе не является проблемой. Это абсолютно допустимый тип отношений, хотя и несколько непрактичный в реализации. Двусторонняя ассоциация добавляет еще одну зависимость, и каждая дополнительная зависимость увеличивает связь (см. «Низкая связь», объясненная Крейгом Ларманом как часть его принципов GRASP).

Тем не менее, иногда необходимо двустороннее объединение, чтобы отразить тот факт, что два объекта имеют смысл только вместе. Да, вы можете сказать, что у фигуры есть доска, но мы действительно так говорим в реальной жизни? Мы заботимся об этом? С точки зрения домена, это не играет решающей роли, по крайней мере, когда домен просто играет чеки. Возможно, в другой воображаемой области, где мы перемещаем фигуры между многими досками, эта точка зрения может иметь решающее значение, и нам может потребоваться смоделировать ее с помощью двусторонней ассоциации. Теперь, упомянув домены, я не могу не упомянуть классическую книгу Эрика Эванса о доменном дизайне. На самом деле, Эрик прекрасно объясняет все нюансы моделирования доменов с помощью программного обеспечения. В частности, он также объясняет двусторонние (двунаправленные) ассоциации между объектами (стр. 83).

Теперь ко второму вопросу. Необходимость хранить ссылку на доску в вашем случае и поддерживать двустороннюю связь вызвана тем, что вы возложили ответственность за перемещение фигур на неправильный объект. Перемещение фрагментов - это операция, которая может затрагивать несколько фрагментов, поэтому один конкретный фрагмент не может справиться с этим, не нарушив инкапсуляцию. Вместо этого мы должны спросить, кто является тем ответственным объектом, который может наблюдать за всеми частями и управлять ими надлежащим образом в соответствии с правилами домена (правилами игры чеков)? Без добавления каких-либо специальных объектов, из тех, что у нас уже есть, это, кажется, доска. Доска выглядит хорошим местом для хранения логики, которая манипулирует содержимым платы (поэтому мы уважаем инкапсуляцию).

Итак, отвечая на ваш реальный вопрос, было бы лучше поместить метод move () в класс Board и автоматически избавиться от ненужной двусторонней ассоциации. И в качестве продолжения того, что я упомянул о распределении обязанностей, я бы снова упомянул GRASP (что на самом деле означает Принципы общего распределения ответственности) - проверьте его, я уверен, что он очень поможет в этом и подобных случаях.

2 голосов
/ 14 марта 2019

Круговая зависимость приводит к жесткой связи.Обычно это считается плохой практикой.Плотно связанные компоненты зависят друг от друга.В тот момент, когда вы решите изменить класс Board, может случиться так, что вам тоже придется изменить класс Piece.И если система растет, эта задача становится все более и более трудной.

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

public class Board {

    public void move(Piece piece, int x, int y) {

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...