В статье, перевод которой предлагается ниже, Роберт Мартин вроде бы начинает с мыслей, очень похожих на те, которые можно увидеть в рассуждениях Егора Бугаенко об ОРМ, но выводы он делает иные.
Лично мне нравится подход Егора, но думаю, что Мартин раскрывает тему более подробно.
Мне кажется, с его мнением стоит ознакомиться всем, кто хоть раз задумывался о том, какое место должен занимать ORM и вообще, зачем нужны объекты со всеми полями открытыми.
Статья написана в жанре «Диалог», где более опытный программист обсуждает проблему с менее опытным.
Что такое классКласс — это спецификация набора похожих объектов.
Что такое объект?Объект — это набор функций, которые выполняют действия над инкапсулированными данными.
Или лучше сказать, объект — это набор функций, которые выполняют действия над данными, существование которых подразумевается.Что значит «подразумевается»?
Поскольку у объекта есть функции, то можно предположить, что данные там тоже есть, но прямого доступа к данным нет и их вообще не видно снаружи.Разве данные не находятся в объекте?
Возможно, они и есть, но не существует правила, гласящего, что они должны быть там.Давайте предположим.С точки зрения пользователя объект — это не что иное, как набор функций.
Данные, с которыми работают эти функции, должны существовать, но местонахождение этих данных пользователю неизвестно.
Хорошо, что такое структура данных?Структура данных — это совокупность связанных элементов.
Или, другими словами, структура данных — это набор элементов, с которыми работают функции, существование которых подразумевается неявно.ЛАДНО ЛАДНО.
Я понимаю.
Функции, работающие со структурами данных, внутри этих структур не определены, но из самого существования структуры данных можно сделать вывод, что должно быть что-то, что с ними работает.
Верно.В каком-то смысле они являются противоположностями друг друга.И что можно отметить по поводу этих двух определений?
Действительно.Ух ты! Вот и получается, что объекты и структуры данных — это не одно и то же!Они дополняют друг друга.
Как рука и перчатка.
- Объект — это набор функций, которые работают с элементами данных, существование которых неявно.
- Структура данных — это набор элементов данных, с которыми оперируют функции, существование которых подразумевается неявно.
Верно.И таблицы в базах данных тоже не являются объектами, верно?Структуры данных — это DTO.
Опять правда.Подождите минуту.Базы данных содержат структуры данных, а не объекты.
Разве ORM не сопоставляет таблицы из базы данных с объектами?
Конечно, нет. Невозможно сопоставить таблицы базы данных с объектами.Тогда что делают ORM?Таблицы в базе данных представляют собой структуры данных, а не объекты.
Они передают данные из одной структуры в другую.Получается, они не имеют никакого отношения к Объектам?
Ничего вообще.Но мне сказали, что ОРМ собирают бизнес-объекты.Строго говоря, не существует такого понятия, как ORM в смысле технологии, отображающей реляционные данные в объекты, потому что невозможно сопоставить таблицы из базы данных с объектами.
Нет, ORM извлекают данные из базы данных, с которой работают бизнес-объекты.Но разве эти структуры данных не относятся к бизнес-объектам?
Может быть, они туда доберутся, а может быть, и нет. ОРМ ничего об этом не знает.Но разница чисто смысловая.
Не совсем.Например?Здесь есть далеко идущие последствия.
Например, проектирование схемы базы данных и проектирование бизнес-объектов.?Эм-м-м.Бизнес-объекты определяют бизнес-поведение.
Схема базы данных определяет структуру бизнес-данных.
Эти структуры сдерживаются совершенно разными силами.
Структура бизнес-данных не обязательно является лучшей структурой для делового поведения.
Это не ясно.
Подумайте об этом таким образом.Ясно.Схема данных не предназначена для одного приложения, она предназначена для использования в масштабах всего предприятия.
Таким образом, структура данных представляет собой компромисс между несколькими различными приложениями.
Отлично.ААА понятно.Теперь подумайте о каждом отдельном приложении.
Объектная модель каждого приложения описывает структуру поведения приложения.
Каждое приложение будет иметь собственную объектную модель, которая лучше соответствует поведению приложения.
Поскольку схема данных является компромиссом между различными приложениями, она не будет навязываться объектной модели каждого отдельного приложения.
Верно! Объекты и структуры ограничены разными вещами.Я помню что-то вроде этого.Они очень редко подходят друг другу.
Люди называют это объектно-реляционным несоответствием импедансов.
Но похоже рассогласование импедансов исправили с помощью ORM.
И теперь вы знаете, что это не так.Что?Несоответствие импедансов между объектами и структурами данных является дополнительным, а не изоморфным.
Это противоположности, а не нечто подобное.Противоположности?
Да, очень интересным образом.Что?Видите ли, объекты и структуры данных предполагают наличие диаметрально противоположных управляющих структур.
Представьте себе набор классов, реализующих некий общий интерфейс.Почему во все примеры цифры пихают код с объектами?Например, представьте себе классы, представляющие двумерные фигуры, имеющие функции для вычисления площади и периметра фигуры.
Давайте рассмотрим два разных типа фигур: квадраты и круги.Помедленнее, пожалуйста, ничего не ясно.Понятно, что функции вычисления площади и периметра этих классов используют разные структуры данных.
Также ясно, что эти операции вызываются с использованием динамического полиморфизма.
Существует две разные функции для расчета площади: одна для квадрата и одна для круга.ХОРОШО.Когда функция вызывается для вычисления площади конкретного объекта, именно этот объект решает, какую конкретную функцию вызывать.
Это называется динамическим полиморфизмом.
Конечно.
Объект знает, как реализованы его методы.
Естественно.
Теперь давайте превратим эти объекты в структуры данных.Дискриминировал что?Мы используем дискриминационные профсоюзы.
Дискриминационные профсоюзы.Поле с кодом будет перечислением?Ну, C++, указатели, ключевое слово объединения, флаг для определения типа структуры, Размеченные объединения.
В нашем случае это просто две разные структуры данных.
Один для квадрата, другой для круга.
Круг имеет центральную точку и радиус.
И код типа, по которому можно понять, что это Круг.
Ну да.ХОРОШО.А у Квадрата будет верхняя левая точка и длина стороны.
А также перечисление для указания типа.
Будет две структуры с кодом типа.
Верно.Хорошо.Теперь давайте посмотрим на функцию площади.
Наверное, там будет переключатель, да?
Конечно, за два занятия.
Ветка для Квадрата и для Круга.
А для периметра тоже понадобится аналогичный выключатель.
И снова правда.Хорошо, я понимаю, к чему вы клоните.Теперь подумайте об этих двух сценариях.
В объектном сценарии две реализации функций площади независимы друг от друга и принадлежат (в некотором смысле) непосредственно типу.
Функция определения площади Квадрата принадлежит Square, а функция определения площади Круга принадлежит Circle.
В сценарии структуры данных обе реализации функции площади находятся в одной и той же функции; они не «принадлежат» (что бы ни означало это слово) к этому типу.
Дальше лучше.Нет необходимости вообще что-либо менять.В случае с объектами, если вам нужно добавить тип «Треугольник», какой код следует изменить?
Просто создайте новый класс Triangle. Хотя нет, наверное надо подправить код, создающий объекты.
Верно.Тогда вам придется добавить его ко всем трем типам: Круг, Квадрат и Треугольник.Итак, при добавлении нового типа изменения незначительны.
Теперь предположим, что нам нужно добавить новую функцию — например, функцию определения центра.
Отлично.А вот со структурами данных все по-другому.Оказывается, добавлять новые функции сложно, потому что приходится вносить изменения в каждый класс.
Чтобы добавить треугольник, вам придется изменить каждую функцию, чтобы добавить ветви к каждому переключателю для обработки треугольника.
Верно.Но для того, чтобы добавить функцию для центра, не нужно ничего менять.Добавлять типы сложно; вам придется редактировать каждую функцию.
Да, добавить функции легко.Ух ты.
Оказывается, эти два подхода прямо противоположны.
Определенно да.Давайте подведем итоги
- Добавлять новые функции в классы сложно; вам придется вносить изменения в каждом классе
- Добавлять новые функции для структур данных легко, нужно просто добавить функцию, больше ничего менять не нужно.
- Добавлять новые типы в классы легко, вам просто нужно добавить новый класс.
- Добавлять новые типы для структур сложно, нужно исправлять каждую функцию
Противоположности.
Противоположности в любопытном смысле.
То есть, если вы заранее знаете, что нужно добавлять новые функции, удобно использовать структуры данных.
Но если вы заранее знаете, что вам придется добавлять новые типы, то вам нужно использовать классы.
Хорошее наблюдение! Но сегодня нам нужно подумать еще об одном.Зависимости?Есть еще один смысл, в котором структуры данных и классы являются противоположностями друг друга.
Зависимости.
Да, направление зависимостей в исходном коде.Хорошо, я спрошу.
В чем разница?
Давайте посмотрим на случай структур.Да, именно так.Каждая функция содержит переключатель, который выбирает нужную реализацию на основе кода типа в объединении.
И что?
Давайте посмотрим на вызов функции для площади.Что вы имеете в виду, когда говорите «зависит»?Вызывающий код зависит от функции области, а функция области зависит от каждой конкретной реализации.
Представьте, что каждая реализация функции площади выделена в отдельную функцию.Что ж, получается, что ветки коммутатора будут просто вызывать эти функции.То есть будут функции CircleArea, SquareArea и TriangleArea.
Представьте, что эти функции находятся в разных файлах.Тогда в файле переключателя будет импорт или использование или включение для файлов с функциями.
Точно.Исходный код переключателя зависит от исходного кода, в котором находятся реализации.Это зависимость на уровне исходного кода.
Один источник зависит от другого источника.
Как направлена эта зависимость?
А как насчет кода, вызывающего функцию площади?Код вызова зависит от кода коммутатора, который зависит от всех реализаций.
Верно.Ладно, ладно, я понимаю, к чему вы клоните.Во всех источниках стрелка направлена по направлению вызова, от вызывающего кода к реализации.
Итак, если вы хотите внести небольшие изменения в эти реализации.
Изменение любой из реализаций повлечет за собой перекомпиляцию всех файлов с переключателем, а это приведет к тому, что будет перекомпилировано все, что вызывает этот переключатель, например, в нашем случае функция для площади.
Да.И это вообще все системы со статической типизацией, да?По крайней мере, так будет с языками, которые используют даты изменения файлов, чтобы понять, что нужно пересобрать.
Да и некоторые другие системы без негоЭто очень много, чтобы собрать заново.
А еще есть много передислокаций.Хорошо, а в случае с классами все наоборот?
Да, потому что код, вызывающий функцию площади, зависит от интерфейса, и реализация также зависит от этого интерфейса.Ясно.
Код класса Square будет импортировать, использовать или включать файл с интерфейсом Shape.
Верно.О да, я понял.Стрелка в файлах реализации указывает в направлении, противоположном вызову.
Он направляется от кода реализации к вызывающему коду.
По крайней мере, так будет для статически типизированных языков.
Для динамически типизированных языков код, вызывающий функцию для области, вообще ни от чего не зависит, поскольку связывание происходит во время выполнения.
То есть, если вы внесете изменения в одну из реализаций.
Только код с этими изменениями нужно пересобрать и переразвернуть.Это связано с тем, что зависимости направлены противоположно направлению вызовов.
Да, мы называем это инверсией зависимостей.Хорошо, позвольте мне подвести итог.
Классы и структуры данных противоположны по трем причинам.
- Функции существуют в классах явно, но о существовании данных можно только догадываться.
Структуры данных явно содержат данные, но о том, какие там функции, можно только догадываться.
- С классами добавлять типы легко, но добавлять функции сложно.
Со структурами добавлять функции легко, но добавлять типы сложно.
- Структуры данных приводят к перекомпиляции и повторному развертыванию вызывающего кода.
Классы изолируют вызывающий код и не требуют повторной компиляции и развертывания.
Да все верно.Теги: #программирование #java #ООП #структуры данных #структуры данных #Роберт Мартин #чистый код #Егор Бугаенко #дядя Боб #объектыИ каждый дизайнер и архитектор программного обеспечения должен помнить об этом.
-
Обзор Sony Vaio Vpcf11M1E/H
19 Oct, 24 -
Что Почитать О Нейронных Сетях
19 Oct, 24 -
Сертификация Товаров В Рф Или 9 Кругов Ада
19 Oct, 24 -
Счастливый Фермер!
19 Oct, 24 -
Extjs На Русском Языке
19 Oct, 24 -
Для Новичков О Seo
19 Oct, 24 -
Тени Персонажей В Видео The Blacksmith
19 Oct, 24 -
Корректная Работа С Датой И Временем
19 Oct, 24