Содержание курса

6.    Паттерны проектирования применительно к сущностям

В 1950 году математик по имени Клод Шеннон опубликовал в журнале статью «Как запрограммировать компьютер для игры в шахматы». В этой статье он подсчитал, что количество комбинаций в шахматах будет равно 10120. Это на самом деле превосходит количество атомов в известной Вселенной, которое оценивается от 1078 до 1082 атомов.

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

По факту этот пример иллюстрирует использование формализованных шаблонов успешных тактических розыгрышей для предсказуемого достижения желаемых результатов.

Подобным образом успешные шаблоны используют и в ИТ. Для того, чтобы при решении однотипных задач проектирования не изобретать каждый раз велосипед, принято использовать паттерны проектирования. Давайте рассмотрим некоторые из них, применительно к моделированию хранилищ данных.

Приспособленец (Flyweight) - структурный паттерн проектирования, который нужен для эффективной работы с большим количеством мелких объектов.

Основная идея: разделить общее состояние объектов и вынести его в отдельное место, чтобы не плодить кучу таблиц и связей, экономить место. При этом объект, представляет себя как уникальный экземпляр в разных местах программы, но фактически не являющийся таковым.

Предполагает обычно использование двух таблиц:

  • Тип объекта — общая часть для многих объектов (например: Приоритет, Пол, Вид заявки).

  • Перечень значений — уникальное для каждого объекта (например: Срочный, Средний), с указанием к какому типу относится.

Пример паттерна Приспособленец
Пример паттерна Приспособленец

Если нам необходимо использовать множество небольших Справочников, например, «Приоритет», «Тип Бронирования», «Вид заявки», «Тип читателя», "Пол" и прочие, то добавление класса для каждого такого справочника приведет к созданию большого количества объектов, которые придется поддерживать. Какие же есть альтернативы?

Можно создать класс, "Тип параметра" и связанный класс "Значение параметра" смотри на рисунок выше. В качестве типов используем название перечисленных нами мини-справочников. А в качестве значений, содержание строк этих справочников, с ссылкой относящей к типу. Для такого варианта желательно также реализовать интерфейс, который по типу справочника, позволит работать с ним как с отдельным объектом системы.

Компоновщик (Composite) - это структурный паттерн проектирования, который нужен, чтобы работать одинаково с отдельными объектами и группами объектов.

Ключевая идея: дерево объектов, где отдельный элемент и группа элементов — одно и то же с точки зрения клиента.

Удобно применять если необходимо:

  • Организовать иерархию объектов (например, папки и файлы).

  • Иметь возможность работать единообразно как с одним файлом, так и с целой папкой.

  • Проводить операции рекурсивно: считать размер папки, удалить всё внутри, найти что-то и т.д.

Пример паттерна Компоновщик
Пример паттерна Компоновщик

В качестве примера, можно рассмотреть универсальный Классификатор, который представляет из себя класс группы и класс «значений», входящих в группу (соответствует паттерну Приспособленец). Для присваивания значения классификатора некому объекту, используется класс «Классификация объекта», который сопоставляет в себе ссылки на: 1)Группу классификатора, 2)Значение классификатора и на 3)Объект системы, к которому применяется классификация с указанием содержания(значения). Да, структура денормализованая, но в этом решении есть свои нюансы. При этом таблица Классификатор содержит рекурсивную ссылку на себя и позволяет строить древовидную структуру. Так же для управления правилами выбора можно использовать дополнительные характеристики. Например, "Один из", указывающую на возможность выбрать только одно или множество значений из группы и характеристика "Можно выбрать", указывающая на возможность /невозможность выбрать элемент на текущем уровне иерархии.

Как можно привести рассмотренную модель к Нормальным формам (NF)? Какие преимущества в данном контексте дает денормализованная форма?

Заместитель (Proxy) - это структурный паттерн, который ставит объект-посредник между клиентом и реальным объектом.

Ключевая идея: клиент работает как будто с реальным объектом, но на самом деле общается с "заменителем", который, например, контролирует доступ, добавляет поведение, откладывает загрузку, логирует, проверяет права и так далее.

Пример паттерна Заместитель
Пример паттерна Заместитель

Например, на рисунке выше, Пользователь не имеет доступ к значениям Классификатора напрямую. Он может обратиться к интерфейсу, который в соответствии с правами доступа, указанными в таблице «Редактор классификатора», предоставит информацию только о доступных пользователю Классификациях.

Примеры применения паттерна Заместитель:

  1. Virtual Proxy - Лениво загружает файлы или каталоги только при обращении

  2. Protection Proxy - Проверяет права пользователя перед доступом к данным

  3. Remote Proxy - Делает вид, что работает с локальным хранилищем, но на самом деле — через сеть (например, через API)

  4. Caching Proxy - Кэширует файлы, метаданные или результаты запросов

  5. Logging Proxy - Логирует все обращения к данным

Фасад (Facade) - структурный паттерн проектирования, который предоставляет упрощённый интерфейс к сложной подсистеме.

То есть, вместо того чтобы клиент "разрывался" между разными сервисами, классами, модулями, он работает через одно общее «окно доступа».

Например, класс Формуляр книги, может собрать всю информацию о книге, компонуя ее из разных классов. Включая: место хранения, каталогизатор, историю выдачи издания и прочее.

Пример паттерна Фасад
Пример паттерна Фасад

Состояние - Используется в тех случаях, когда во время выполнения программы объект должен менять своё поведение в зависимости от своего состояния.

Например, в зависимости от текущего статуса книги, для нее доступна одна из операций «Выдача» или «Возврат».

Пример паттерна Состояние
Пример паттерна Состояние

Преимущества паттерна Состояние для хранилищ:

  • Поведение хранилища чётко связано с текущим состоянием, без нагромождения условных переходов.

  • Легко добавлять новые состояния без переписывания всей логики.

  • Повышается читаемость и расширяемость кода.

  • Удобно покрывать тестами каждое состояние отдельно.

Паттерн Состояние очень удобно использовать совместно с диаграммами BPMN, для "умного" выбора действия над объектом, из доступного ассортимента в текущем состоянии . В следующей части мы будем разбирать поведенческие модели и в том числе диаграмму Состояний.

Коллаборация паттернов Фасад (Facade) / Состояние (State)

1)  Фасад (StorageFacade) — это единая точка входа для клиента. Клиенту не нужно знать о состоянии, он просто вызывает метод.

2)  Состояние (StorageState) — определяет, как именно работают методы в зависимости от текущего состояния хранилища:

  • инициализация,

  • рабочее состояние,

  • ошибка,

  • миграция и т.д.

3)  Фасад внутри себя держит ссылку на состояние и перекидывает вызовы методам состояния.

Прототип (Prototype) - порождающий паттерн, который, позволяет создавать новые объекты копированием уже существующего экземпляра-прототипа, вместо создания объекта с нуля через конструктор.

Иными словами, можно копировать существующий объект в новый, вместо его создания с "0". Это быстро, удобно, без необходимости всё настраивать заново.

При этом используется инструмент - "Реестр прототипов", представляющий хранилище (словарь), где мы:

1)    регистрируем прототипы (например, LocalStorage, S3Storage, InMemoryStorage);

2)    по запросу клонируем нужный прототип;

3)    при необходимости — донастраиваем клоны.

7.    Адаптивные модели данных

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

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

Шаблонный метод (Template method) - паттерн проектирования (поведенческий), который: определяет скелет алгоритма в методе базового класса, а отдельные шаги этого алгоритма делегирует на переопределение в подклассы.

Иными словами: базовый класс описывает общий план действий. Подклассы могут кастомизировать детали, не меняя структуру процесса. Определяет основу алгоритма и позволяет наследникам переопределять некоторые шаги алгоритма, не изменяя его структуру в целом. На диаграмме ниже представлен пример организации шаблона "Карты заданий", позволяющий быстро и точно создавать цепочки задач для исполнителей.

Пример паттерна Шаблонный метод
Пример паттерна Шаблонный метод

Аналитик, встретив необходимость преодоления некой проблемы, схожей с той которую прежде уже решал, должен универсализировать это решение при помощи шаблона.

Используйте рефакторинг процессов моделирования, обращаясь к паттернам проектирования, в том числе создавайте свои шаблоны.

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

В следующей части мы рассмотрим моделирование поведения.

Комментарии (0)