Монопольная игра - принцип LSP OO

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

(Просто примечание: этот проект личный и просто для развлечения, поэтому мне на самом деле все равно, насколько код удобен в сопровождении, но я просто прошу личного обучения и понимания LSP)

Позвольте мне начать с того, что я разработал до сих пор:

Класс BoardSpace — это абстрактный базовый класс, и на каждый «вид» пространства на доске приходится по одному подклассу. Итак, у меня есть PropertySpace, TaxSpace, GoSpace и т. д.

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

Но кажется, что это противоречит LSP в том, что все эти различные Land() переопределенные методы будут делать совершенно разные вещи, как я их и разработал.

Или я неправильно понимаю LSP? Это больше связано с тем, как Land() "ожидается" или "описывается" работа? Который в этом случае полностью отличается для каждого места, так что все в порядке? Или это конечно нарушение и надо переделывать?

Дополнительный вопрос: будет ли это считаться «злоупотреблением» наследованием или его хорошим использованием?


person Community    schedule 27.01.2012    source источник


Ответы (1)


В LSP вполне допустимо, чтобы методы подкласса выполняли действия, совершенно отличные от методов суперкласса, если они не нарушают контракт суперкласса. Так что на самом деле все зависит от того, насколько широким вы сделаете этот контракт.

Если бы BoardSpace.Land() было разрешено только изменять состояние игрока, тогда у вас была бы проблема, если бы приземление подкласса позволяло игроку купить его (изменение состояния пространства). Однако, если Land() разрешено изменять состояние приземляющегося игрока и игрока-владельца, состояние пространства и состояние колоды карт, то нарушение LSP отсутствует.

Тем не менее, может быть хорошей практикой разбивать вещи на более мелкие методы, о которых вы можете рассуждать более точно. Например, при приземлении на поле может быть выполнено специальное действие (например, взятие карты), за которым следует транзакция между игроком и владельцем поля (другим игроком или банком) с ограничением, что действие может влияет только на деньги и карты игрока и колоды карт, а транзакция может повлиять только на деньги двух вовлеченных сторон и право собственности на пространство.

person Russell Zahniser    schedule 27.01.2012
comment
Ну, я не стал вдаваться в подробности того, что на самом деле делает Land(). У меня есть нечто большее, чем ТОЛЬКО это. На самом деле мои пространства никогда не меняют состояния; вместо этого PropertySpace содержит объект Property, который может изменяться. Итак, не могли бы вы сказать, что в LSP контракт должен быть определен как минимум, необходимый для того, чтобы делать то, что должен делать объект? Например, Land() может изменить только то, что разрешено изменить в правилах Монополии о приземлении на любое место (которые в данном случае оказываются довольно широкими)? - person ; 27.01.2012
comment
Например, в известном примере Rectangle/Square контракт getArea() возвращает ширину * высоту... для всех подклассов. Вот почему Square его нарушает, потому что, когда вы setWidth(50); setHeight(10); ожидаете 500 по контракту. Итак, LSP очень зависит от контракта... я на правильном пути? - person ; 27.01.2012