Инкапсуляция объекта vs инкапсуляция поведения
Рассмотрим два подхода к программированию.
Использование полноценных логических объектов которые что-то могут.
И использование разного рода статических функций и классов для обработки объектов.
Итак. ООП нас учит таким правилам как инкапсуляция и наследование.
Инкапсуляция это типа как объединить некий срез логики в одном месте, в одном классе (на пару уровней выше можно уже рассматривать инкапсуляцию на уровне модулей, к примеру, но сейчас пока не об этом). Наследование это к примеру мы уже сделали некий инкапсулированный объект - табуретка. Хотим написать стул. Стул - это табуретка со спинкой. Соответственно берем, наследуемся стулом от табуретки. И автоматически наш стул уже умеет всё то что умела табуретка, и имеет все свойства которые имела табуретка. Добавляем в нее спинку и методы, которые со спинкой связаны - вуаля. Написали пять строчек и стул готов. А всё благодаря к тому что мы уже раньше постарались и написали табуретку.
Так вот наследование это конечно круто, если не пытаться смешивать роды и виды с подвидами. Иногда бывает очень сложно классифицировать эти все семейства разнородных сущностей. Только тема не об этом.
А тема вот о чем.
Вот к примеру есть у нас табуретка.
У нее есть свойства:
- 4 ножки.
- Восседалище.
С ней можно что-то делать (методы):
- сидеть на ней
- двигать
- кидать
- ломать
- прочее
А еще у нас есть тумбочка.
У нее тоже есть свойства:
- 4 ножки
- вместилище
- дверки
С ней можно что-то делать (методы):
- положить в нее что-то
- двигать ее
- кидать
- ломать
//****************************************
Так собственно вот.
Что мы можем с этим всем сделать.
Вариантов у нас на самом деле два, а не один, как может сразу показаться.
Первый. Очевидный - сделать базовый класс "мебель", с примерно следующим составом:
Свойства
- ножки
- размер
- вес
Методы
- двигать
- кидать
- ломать
Далее этот базовый класс расширяем табуреткой и тумбочкой. Соответственно в табуретке дописывается восседалище, а в тумбочке вместилище и вуаля.
Но мы ведь можем пойти и другим путем.
Например у нас есть изометрическая карта. На ней есть стопицот всего. Например это таки комната. В ней может быть мебель, могут быть НПЦ, могут быть враги, друзья, мусор и прочая муть.
И например нам это всё надо уметь перемещать.
В таком случае касательно тумбочки и табуретки мы можем убрать методы перемещения. Написать статик класс "перемещатор", с методом:
переместить(объект, координаты).
И пользоваться этим методом для ВСЕХ объектов, которые мы можем перемещать по этой карте. Таким образом мы инкапсулировали ПОВЕДЕНИЕ в отдельный класс и отдельный метод. Функционал перемещения то один и тот же. Объект был на клетке такой-то, переехал в клетку такую-то. Зачем это всё писать в каждом отдельном классе, или же придумывать какую-то нереальную цепочку наследования мусора и табуретки от одной сущности?
Таким же образом мы добавляем какой-то статик метод поломать(объект). И у нас появляется поведение для всех ломающихся объектов. Опять же теперь это не нужно реализовывать где-то в объектах с нереальными цепочками наследования.
Со статиками появляются дополнительные задачи, например какие-то интерфейсы по типу ИПеремещабельный, ИРазрушабельный. Но это конкретно темы не касается, потому останавливаться не буду.
//****************************************
Это собственно сама суть.
Первый подход с наследованием и полноценными объектами можно назвать инкапсуляцией объекта, второй со статиками - можно назвать инкапсуляцией поведения (термины не научные и не технические, но я это называю так, так что если к терминологии будут вопросы я готов выслушать и че-то подкорректировать).
//****************************************
Теперь плюсы и минусы подхода.
Вариант с наследованием хорош когда у вас есть четкое дерево наследования, желательно не больше трех последовательных наследований. И к тому же если это оправдано.
Например цепочка мебели. У нас есть класс мебели, от которого все наследуются, и там может где-то еще стул от табуретки а шкаф от тумбочки. Но не более. Если наше дерево распускает ветви на пять уровней в глубину - лучше придумать что-то другое. Да и например есть у вас диван. Вы его откуда отнаследуете? от кресла(мягкое, с быльцами и спинкой, но короткое) или от лавочки в парке(Длинное, с быльцами, спинкой, но не мягкое)?
Второй вариант с делегированием поведения хорош когда вам побоку что двигать. У вас есть разнородный перемещабельный хлам. Вот вы его и перемещаете. А мебель это, или мусор, или камни, или стены - вам пофиг. Объект имплементит перемещабельный интерфейс и вуаля. В одном месте написан метод перемещения и всем хорошо. Но это становится плохо, когда визуально перепмещение отличается у стула и у мусора например. Стул просто передвигается, мусор перекатывается. Уже надо думать где что использовать.
//****************************************
Соответственно использование статиков это как раз про второй вариант. Если у вас есть возможность инкапсулировать какое-то поведение - вы его выносите в статик класс.
Так же, например, с той жк изометрической картой вам часто надо считать координаты и переводить пиксели в изометрические х-у. В таком случае опять же выносим метод подсчета координат в в статик метод в какие-то IsoUtils.
Или у вас есть желание разрушать объекты, но не охота писать в каждом классе дестроеры, как это принято в плюсах. Опять же можно написать какой-то универсальный метод для этих целей, и больше не заморачиваться.
//****************************************
В статиках нет ничего плохого либо хорошего. Это как еще одна отвертка в вашем наборе инструментов. Главное знать где его правильно использовать

Ну и как верно заметил в комментариях товарищ ChuwY - такого же эффекта инкапсуляции поведения можно добиться еще многими методами кроме статиков. Статик это самый простой в использовании вариант. Но не стоит им злоупотреблять. Как и любой другой инструмент нужно использовать к месту.
Идеальный вариант для стстика это классы по типу Math, в которых ничего не сохраняется, функция отработала, выдала результат и больше о ней не вспоминаем. Если же функция в процессе что-то куда-то сохраняет - при неправильной организации вполне можно ожидать утечек памяти или иных неприятных последсвий.
Как-то так. Искренне ваш.
Всего комментариев 11
Комментарии
![]() ![]() |
|
Жаль, что в AS нет множественного наследования
![]() |
![]() ![]() |
|
Мне кажется что автор описал паттерн Entity Systems. Который, кстати, вполне себе может заменить множественное наследование (в контексте нескольких поведнеий у одного объекта)
|
![]() ![]() |
|
по поводу entity есть отличная статья на хабре, но большая )
|
![]() ![]() |
|
Цитата:
описал паттерн Entity Systems
![]() Entity system это не совсем паттерн, это больше подход опять же. И там юзается по больше части не статик, а композиция из микроповедений. Добавил пару примеров, мб понятнее будет. Цитата:
Жаль, что в AS нет множественного наследования
Скрестил собаку с птичкой, родил генетического урода, не способного к жизни, и молодец. |
|
Обновил(-а) Dukobpa3 15.11.2013 в 14:22
|
![]() ![]() |
|
Все хорошо.
Только инкапсулировать поведение можно не только в статике ![]() |
![]() ![]() |
|
Есть например чудесный паттерн стратегия.
И еще много всяких энтити систем. Но статья была о статиках ![]() ![]() |
![]() ![]() |
|
![]() ![]() |
|
С любым подходом можно огрести.
|
![]() ![]() |
|
На самом деле, скорее всего начнется такое:
public class Blah implements IMovable { public function move():Boolean { this.fart(); return true; } } .... public static function movieMovables(value:IMovable):void { if(!value.move()) { value.x=blah; } } Цитата:
по поводу entity есть отличная статья на хабре, но большая )
Цитата:
Архитектура систем сущностей пришла из попытки решить проблемы игрового цикла. Она делает игровой цикл ядром игры и предполагает, что упрощение игрового цикла важнее, чем все остальное в архитектуре современной игры. Это важнее, чем отделить вид от контролера, к примеру.
|
|
Обновил(-а) DCH 11.12.2013 в 09:54
|
Последние записи от Dukobpa3
- Strategy (Стратегия) (27.12.2013)
- State (Состояние) (27.12.2013)
- State-machine (конечный автомат, машина состояний) (25.12.2013)
- Медиатор, Прокси (14.11.2013)
- Инкапсуляция объекта vs инкапсуляция поведения (14.11.2013)