Traits and Mixins Are Not OOP

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

Сразу скажу, что особенности, о которых мы будем говорить здесь, являются чистым “ядом”, внедренным в объектно-ориентированное программирование теми, кто отчаянно нуждался в лоботомии, как и предложил Дэвид Уэст в своей книге “Мышление объектами”. У этих особенностей есть разные названия, но наиболее распространены traits и mixins. Я серьезно не понимаю, как мы до сих пор можем называть программирование объектно-ориентированным, когда оно имеет эти особенности.

Во-первых, давайте рассмотрим, как они работают вкратце. Давайте в качестве примера возьмем модули Ruby. Предположим, у нас есть класс Book:

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

Или мы можем сделать это еще более “удобным” и расширить наш модуль, чтобы иметь прямой доступ к его методам.

Кажется хорошо, если вы не понимаете разницу между объектно-ориентированным программированием и статическими методами. Более того, если мы на минутку забудем о чистоте ООП, этот подход на самом деле выглядит менее читаемым для меня, хотя в нем меньше символов; трудно понять, откуда берется метод caps(), когда он вызывается просто как #{caps(@title)}, а не #{TextUtils.caps(@title)}. Не так ли вы считаете?

Миксины начинают играть свою роль лучше, когда мы их включаем (include). Мы можем комбинировать их, чтобы создать поведение класса, которое нам нужно. Создадим два миксина. Первый будет называться PlainMixin и будет выводить заголовок книги так, как он есть, а второй будет называться CapsMixin и будет делать буквы заголовка прописными, если они уже были выведены:

Вызов Book без включенного миксина выведет его заголовок так, как он есть. Как только мы добавим оператор include, поведение to_s будет переопределено, и метод print будет давать другой результат. Мы можем комбинировать миксины, чтобы получить необходимую функциональность. Например, мы можем добавить еще один, который сократит заголовок до 16 символов.

Я уверен, вы уже понимаете, что оба имеют доступ к приватному атрибуту @title класса Book. Фактически, у них есть полный доступ ко всему в классе. Они буквально являются “кодовыми фрагментами”, которые мы “внедряем” в класс, чтобы сделать его более мощным и сложным. Что не так с этим подходом?

Это та же проблема, что и с аннотациями, DTO, геттерами и утилитарными классами - они разбивают объекты на части и размещают функционал в местах, где объекты их не видят.

В случае с миксинами функционал находится в модулях Ruby, которые делают предположения о внутренней структуре Book и дополнительно предполагают, что программист все еще будет понимать, что находится в Book после изменения внутренней структуры. Такие предположения полностью нарушают саму идею инкапсуляции.

Такая тесная связь между миксинами и приватной структурой объекта приводит только к неподдерживаемому и сложно понятному коду.

Очевидные альтернативы миксинам - это компонуемые декораторы. Взгляните на пример, приведенный в статье:

Не похоже ли это очень на то, что мы делали выше с помощью смешивания Ruby?

Однако, в отличие от смешивания, декораторы оставляют объекты небольшими и связными, добавляя дополнительную функциональность поверх них. Смешивание делает наоборот - оно делает объекты более сложными и, благодаря этому, менее читаемыми и поддерживаемыми.

Я искренне считаю их ядом. Тот, кто их придумал, явно не разбирался в философии объектно-ориентированного дизайна.

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-17 at 16:43

sixnines availability badge   GitHub stars