Pull to refresh

Comments 10

Кажется, получается нечто переходное между data-oriented design и object-oriented design.
А про композицию все забыли? Наследование не является единственным способом единожды определить общий для нескольких классов функционал.
Вопрос навскидку. В каком отношении находятся классы «Квадрат» и «Прямоугольник»?

Не уверен, что классы «Утка» и подкласс «Утка, умеющая стрелять из ПЗРК», будут соответствовать substitution-принципу. Подкласс сможет поражать цели, что не мог бы делать родительский класс.

Тут обычно говорят «Use composition instead of inheritace».
1. сама идея классов наследников от Персонажа — собирать в единую сущность умения. Другими словами, персонажи изначально композиция умений. Решение сделать композитный класс родителем (корнем иерархии наследования) принято т.к. у этой сущности можно выделить поведение/ответственность/умения общие для всех Уток, что-бы потомки реализовывали специфику. Придерживаясь направления с верху вниз — всё-же персонаж более общий объект нежели умение, соответственно подклассы утки разбирают детали сочетаний разных умений. А подклассы умения стрелять из пзрк — специфику выстрелов определённых классов персонажей (если такая есть для Утки).

2. Функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа, не зная об этом — явного запрета расширять функциональность подклассов я не вижу. В случае работы с Простой Уткой и Уткой умеющей стрелять через интерфейс Утки разницы в функциях не видно: по замыслу обе умеют специфически перемещаться (плавать и нырять). +п1.

3. В каком отношении находятся классы «Квадрат» и «Прямоугольник»?
Хороший вопрос, в данном контексте, заставил задуматься о понятии отношение в его общем смысле.
Если оставаться в рамках статьи отношений было 3: родитель-потомок, находятся в композиции, не соотносятся. Причины выделения сущностей в отношения: уточнение выделенной ответственности, композиция ответственностей для представления сложного объекта.
В вопросе не достаёт полноты — зачем нам в программе понадобились эти понятия, что мы с ними делаем — только после прояснения этого, можно собрать их в одно из указанных отношений.

Заглянув в вики отношение нашлись слова соотнесение, связь — что возможно только при наличии некоторого подобия либо взаимодополняемости нескольких объектов. Соответственно у сферических в вакууме Квадрата и Прямоугольника можно выделить разный набор взаимосвязей (по углам, по ограничениям на длины сторон, ...) но без привязки к конкретике ответа на вопросы из п.3. они так и останутся в вакууме.
Очень хорошо, когда у нас есть только разные виды уток. Неплохо, так же, когда кроме уток есть разные виды котиков.
Но становится очень нехорошо, когда у нас есть стреляющая утка и стреляющий котик, а мы располагаем только наследованием.
Вот тут начинается нетривиальное пересечение умений.
В православных языках запрещено множественное наследование, можно только реализовывать множество интерфейсов, но это ведёт к повторению кода.
Выход их этой ситуации — композиция. Именно так получается то, что никак не связанные друг с другом утка и котик умеют одно и то же.
Причём композиция тоже может наследоваться, когда мы собираем её фабрикой, а потом расширяем фабрику так, чтобы она давала эту же композицию и дополнительно несколько новых умений.
м… кажется мы говорим о похожем но разными словами.
Все наследники Персонажа — по существу композиции навыков какие-то определённые для: Утки, Пехотинца, Котика и т.д.
Класс Персонажа может существовать как базовый, поскольку у всех его потомков есть как минимум процесс добавления/удаления навыков.
Иерархия Персонажей (в смысле потомков) — скорее всего не опуститься глубже 4-го уровня, считая Персонажа 1-м, Утку, Пехотинца, Котика — 2-м, а ниже модификации каждого из них (например необычные типа стреляющей утки и летающего котика).

Добавление котика тут выглядит приблизительно так:
Котик (Персонаж):
  • от родителя: текущее умение передвигаться со значением _ходить на четвереньках_
  • список умений: [ходить на четвереньках, мяукать]


Ходить на четвереньках (Умение ходить):
  • перекрывает основной метод — идти,
  • + специфика


Собственно котик добавлен. Далее странности:

Котик летающий (Котик):
внутри перехватываем команды взлететь/сесть и соответственно подправляем логику поведения при переключении текущего умения передвигаться. Вот эта поправка, может идти 2-мя путями:
  • либо полностью перекрыть метод, продублировав частично из родителя.
  • либо родителя так подогнать, что общие части одинаковы, а разницу с обычным котиком уточнить в потомках. Тогда нужен ещё Обычный котик (Котик) — с нормальным поведением.


Умение летать (умение передвигаться)
перестройка управления для полёта

Умение летать для котика (Умение летать)
особенности полёта котика

Идея поста в этом и состояла, что умение — одно дерево наследования (оно может быть очень развлетвлённым и глубоким с учётом того кто их использует), персонажи — другое но являющееся композицией из умений (и с разумной глубиной в пределах 4-х уровней). В более обобщённом виде персонажи могут в себе агрегировать и другой класс функций (не умения). По другому — агрегация ответственностей — тоже ответственность с ограниченной специализацией.

Хотя всё это рассчитано на то, что количество странных сочетаний не будет расширяться до бесконечности, т.к. появление летающего и стреляющего котика заставит сильно задуматься о том, как-же его получить, и вообще — стоит ли тогда под такое классы с объектами городить в таком прямолинейном подходе (ниже есть ссылка на Entity System, да и в родительском посту что-то подобное в Clojure описано).
Согласен. Просто стиль написания довольно своеобразный, много слов проглатывается пока Вы летаете в своём воздушном замке. Иллюстрация могла бы многое прояснить.
Sign up to leave a comment.

Articles