Укр
Порождающие шаблоны проектирования

Порождающие шаблоны проектирования

  • 10 августа, 2023
  • читать 10 мин
Денис Розганяев
Денис Розганяев Software Engineer в Mobilunity, Преподаватель Компьютерной школы Hillel.

Это вторая часть цикла, посвященного шаблонам проектирования. Первую часть можно прочесть по ссылке ниже.

Рекомендуем публикацию по теме

Что такое порождающие паттерны?

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

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

Порождающие паттерны содержат в себе следующие 2 идеи:

  1. Инкапсуляция знаний о том, какие конкретные классы использует система
  2. Сокрытие функционала, а именно то, как создаются и комбинируются экземпляры этих конкретных классов

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

Когда использовать?

Есть несколько ситуаций, когда рождающие паттерны пригодятся:

  • Система должна быть независимой от того, как создаются ее объекты и продукты
  • Набор связанных объектов предназначен для совместного использования
  • Скрытие реализаций библиотеки классов или продукта, не скрывая только их интерфейсы
  • Построение разного представления независимых сложных объектов
  • Класс хочет, чтобы его подкласс реализовал объект, который он создает
  • Экземпляры класса указываются во время выполнения
  • Должен быть единственный экземпляр, и клиент должен иметь доступ к нему в любое время
  • Инстанс класса должен быть расширяемым без изменений

Есть 5 основных рождающих паттерна, а именно:

  1. Фабричный метод (Factory method)
  2. Абстрактная фабрика (Abstract Factory)
  3. Строитель (Builder)
  4. Прототип (Prototype)
  5. Одиночка (Singleton)

На самом деле их больше, однако мы остановимся на этих 5 и поговорим о них.

Factory Method

Этот паттерн определяет общий интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов.

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

Класс Creator не всегда, но в большинстве случаев является абстрактным классом, который имеет абстрактный метод, в примере ниже это factoryMethod.

factoryMethod должен возвращать объект класса, имплементирующий общий интерфейс (В примере: Product).

Таким образом, у нас есть классы, которые наследуются от Creator, и создают объекты конкретных классов продуктов.

Abstract Factory

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

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

Для правильного построения абстрактной фабрики следует придерживаться следующих действий:

  1. Создать таблицу/матрицу соотношения типов продуктов к семействам продуктов
  2. Свести все вариации продуктов к общим интерфейсам
  3. Создать интерфейс абстрактной фабрики. В нем построить методы для создания каждого продукта
  4. Создать классы фабрик, которые будут реализовывать интерфейс абстрактной фабрики, по принципу 1 фабрика = 1 класс

Builder

Данный шаблон помогает избежать классов с большим количеством аргументов внутри конструктора.

Паттерн проектирования Builder решает такие проблемы, как:

  • Как класс (тот же процесс конструирования) может создавать разные представления сложного объекта
  • Как можно упростить класс, включающий создание сложного объекта
  • Создание и сбор частей сложного объекта непосредственно в классе является негибким. Это обязывает класс создать определенное представление сложного объекта и делает невозможным изменение представления позже независимо от класса (без необходимости изменять).

Шаблон проектирования Builder описывает, как решить следующие проблемы:

  • Инкапсулирование создания и сбора частей сложного объекта в отдельный объект Builder
  • Класс делегирует создание объекта объекта Builder вместо того, чтобы создавать объекты напрямую
  • Класс (тот же процесс строительства) может делегировать разные объекты Builder для создания различных представлений сложного объекта

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

Prototype

Прототип позволяет копировать объекты, не вдаваясь в подробности их реализации.

Шаблон решает такие проблемы, как:

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

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

  • Определите объект Prototype, который возвращает копию
  • Создайте новые объекты, скопировав объект Prototype

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

Singleton

Стоит отметить, что Одиночка считается анти-паттерном!

Этот паттерн гарантирует создание только одного экземпляра класса и предоставляет доступ к этому объекту из любой точки проекта.

Сложно описать диаграммой данный паттерн, поэтому лучше покажу в виде кода.

Рекомендуем курс по теме