Шаблоны проектирования

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

Выделяют три группы шаблонов:
  1. Порождающие (Creational) – описывают создание объектов.
  2. Структурные (Structural) – описывают структурную организацию связей между объектами.
  3. Поведенческие (Behavioral) – описывают поведение объектов.

Ниже перечисляются конкретные шаблоны и примеры их реализации на языке PHP.

Порождающие шаблоны

Порождающие паттерны абстрагируют создание объектов и полезны в случаях, когда создание объектов с помощью конструктора становится обременительным.
  • ОДИНОЧКА (SINGLETON)
    Используется в случаях, где требуется только один объект класса и нужно иметь общую точку доступа к этому объекту.
    Пример задачи: реализация работы с БД. Создаётся единственный объект для подключения к базе и выполнения запросов, причём доступ к объекту должен иметься из любого места кода.
  • ПРОСТАЯ ФАБРИКА (SIMPLE FACTORY)
    Упрощает создание объектов, инкапсулируя логику создания в класс-фабрику, тем самым скрывая её от клиентского кода.
    Пример задачи: создание объектов ценных бумаг (акции, облигации, опционы).
  • АБСТРАКТНАЯ ФАБРИКА (ABSTRACT FACTORY)
    Предоставляет механизм для создания семейств связанных объектов без указания их конкретных классов. Паттерн действует как фабрика фабрик, где главная фабрика создает другие фабрики, которые, в свою очередь, создают конкретные продукты (объекты). Это позволяет в клиентском коде легко переключаться между группами связанных объектов без крупных изменений кода. Пример задачи: реализация тем оформления приборной панели электромобиля.
  • ФАБРИЧНЫЙ МЕТОД (FACTORY METHOD)
    Определяет в родительском классе общую схему создания объекта и даёт дочерним классам  право самостоятельно решать, объект какого класса им нужно создавать. Тем самым, в родительском классе задаётся абстрактная логика, а в дочерних классах реализуется конкретная логика.
    Пример задачи: запись логов на разные носители (вывод на экран, запись в файл на локальном диске, сохранение в базу данных).
  • СТРОИТЕЛЬ (BUILDER)
    Предлагает схему пошагового создания сложных объектов. С помощью этого паттерна, используя один и тот же конструктивный код, можно создавать объекты разных типов или одного типа, но с разным наполнением.
    Пример задачи: создание запросов к БД, используя конструктор запросов.
  • ПРОТОТИП (PROTOTYPE)
    Представляет механизм для массового создания различных объектов с помощью класса-прототипа и последующего копирования однотипных объектов, вместо их создания с нуля.
    Пример задачи: создание армии юнитов на карте игровой стратегии.

Структурные шаблоны

Структурные паттерны оптимизируют и упрощают сложные структуры, организуют связи между объектами.
  • АДАПТЕР (ADAPTER)
    Предлагает прослойку в виде класса-адаптера для совместимости интегрируемого класса и пользовательского кода
    Пример задачи: получение платёжной ссылки для разных систем оплаты.
  • МОСТ (BRIDGE)
    Предлагает разделить крупный монолитный класс на класс-сущность (абстракцию) и классы-функциональности (реализации функций), а затем связать их мостом в виде ссылки. Это позволяет изменять сущность и её функциональности с меньшей зависимостью друг от друга.
    Пример задачи: создание медиаконвертеров.
  • КОМПОНОВЩИК (COMPOSITE)
    Предлагает схему создания составных объектов. Используется при моделировании иерархий, когда ряд объектов необходимо скомпоновать древовидной структурой в одном комплексном объекте.
    Пример задачи: сделать модель коробки, в которую упакован заказ.
  • ДЕКОРАТОР (DECORATOR)
    Предлагает схему для замены исходного объекта новым, который дополняет функционал исходного объекта или изменяет его.
    Пример задачи: в расчёт стоимости доставки груза добавить учёт скидок по бонусной программе.
  • ФАСАД (FACADE)
    Предлагает упрощение работы со сложными структурами (API, классы, наборы функций) с  помощью класса-фасада, который скрывает трудоёмкие процессы и предоставляет клиентскому коду более простые методы работы.
    Пример задачи: упростить получение количества заказов пользователя в CMS Битрикс.
  • ЕДИНАЯ ТОЧКА ВХОДА (FRONT CONTROLLER)
    Предлагает сделать для обработки входящих обращений единый начальный обработчик, который будет выполнять роль точки входа и распределительного центра.
    Пример задачи: создать скрипт для обработки API-запросов.
  • ЛЕГКОВЕС / ПРИСПОСОБЛЕНЕЦ (FLYWEIGHT)
    Предлагает оптимизацию использования объектов, чтобы снизить затраты оперативной памяти и процессора. Оптимизация заключается в вынесении уникальных свойств объектов за пределы объекта, уменьшении количества объектов и построении конструкций, когда клиентский код использует объекты повторно.
    Пример задачи: в списке статей вывести имя автора.
  • ЗАМЕСТИТЕЛЬ (PROXY)
    Предлагает класс-заместитель для перехвата вызываемых методов исходного класса. Паттерн используется для действий, которые нужно выполнить до или после вызова методов исходного класса — например, для логирования, кеширования, проверки прав доступа и других действий. А так как класс-заместитель повторяет публичные свойства и методы исходного класса, то клиентский код не требует внесения больших изменений. По факту, Заместитель выступает в роли прокси-агента между клиентским кодом и исходным классом
    Пример задачи: сделать кэширование статей.

Поведенческие шаблоны

Поведенческие паттерны задают поведение и взаимодействие объектов, распределяют их обязанности.
  • ЦЕПОЧКА ОБЯЗАННОСТЕЙ (CHAIN OF RESPONSIBILITY)
    Предлагает схему для выполнения действия с помощью цепочки обработчиков. Если первый обработчик из цепочки не смог выполнить действие (обязанность), то выполнение переходит ко второму обработчику. Если второй не смог, то выполнение переходит к третьему. И так до конца цепочки или пока действие не будет успешно выполнено.
    Пример задачи: сделать многофильтровое цензурирование текста.
  • КОМАНДА (COMMAND)
    Предлагает связать инициатора действия и его выполнителя с помощью отдельного класса-команды. Тем самым логика работы с выполнителем действия перемещается из инициатора или клиентского кода в класс-команду. Это позволяет упаковать действие в объект и хранить его, добавлять и извлекать из очереди.
    Пример задачи: сделать поочерёдную перезагрузку серверных служб (почтовый сервис, база данных, мемкэш).
  • ИНТЕРПРЕТАТОР (INTERPRETER)
    Предлагает реализовать собственный язык запросов и его интерпретатор. Это позволяет писать выражения, формулы, фильтры, шаблоны, анализировать их, переводить в программные действия и выполнять обработки
    Пример задачи: разработать язык для указания правил проверки корректности значений текстовых полей (возможные проверки: является ли числом, обязательность заполнения поля, проверка величины значения — больше или меньше).
  • ИТЕРАТОР (ITERATOR)
    Предлагает схему для обхода списка элементов. Идея паттерна заключается в том, чтобы за реализацию обхода элементов отвечал отдельный класс-итератор, а не клиентский код или методы класса элементов (контейнера элементов). Это даёт возможность в случае изменения класса элементов сохранить клиентский код и сделать общую реализацию гибкой.
    Пример задачи: обойти очередь событий и вызвать обработчики для определённого вида событий.
  • ПОСРЕДНИК (MEDIATOR)
    Предлагает схему, при которой объекты взаимодействуют между собой не напрямую и явные связи, а через объект-посредник. Это позволяет перенести логику взаимодействия множества объектов в централизованное место – в класс посредника.
    Пример задачи: сделать отправку и приём сообщений между пользователем-клиентом и службой техподдержки.
  • ХРАНИТЕЛЬ (MEMENTO)
    Предлагает схему для сохранения свойств объекта в виде снимка, а также восстановление значений свойств из ранее сохранённого снимка
    Пример задачи: для процесса правки геометрической фигуры «Прямоугольник» реализовать сохранение и загрузку свойств: X, Y, ширина, высота и цвет в виде контрольных точек.
  • НАБЛЮДАТЕЛЬ (OBSERVER)
    Предлагает схему, в которой при изменений объекта другие объекты получают уведомления и могут выполнять различные обработки. Широкое применение  шаблон получил в реализации событий, когда после наступления какого-то события нужно выполнить ряд действий.
    Пример задачи: в момент прихода заказа в пункт выдачи нужно отправить покупателю SMS и письмо с сообщением о доставке заказа.
  • СОСТОЯНИЕ (STATE)
    Предлагает схему кардинального изменения поведения объекта в зависимости от изменения его внутреннего состояния (значений свойств). Это позволяет сделать архитектуру объекта гибкой, снизить количество условных операторов и сократить объём обработок.
    Пример задачи: реализовать превращение игрока в различных живых существ.
  • СТРАТЕГИЯ (STRATEGY)
    Предлагает схему для динамического изменения поведения (функционала) метода объекта. Это позволяет разбить большие обработки на несколько мелких, снизить сложность и сделать архитектуру проекта гибче
    Пример задачи: реализовать возможность вывода отчёта в трёх форматах – текстовый, HTML и MediaWiki.
  • ШАБЛОННЫЙ МЕТОД (TEMPLATE METHOD)
    Предлагает схему, в которой общий порядок работы объекта и каркас алгоритма задаётся в базовом классе, а в дочерних классах объект и алгоритм получают законченную форму, при этом общая логика, намеченная в базовом классе, не нарушается. Под алгоритмом тут понимается выполнение какого-то действия с помощью метода, определённого в базовом классе и который является окончательным. В терминологии шаблона данный окончательный метод и есть шаблонный метод. Дочерние же классы реализуют другие методы, используемые шаблонным методом и тем самым в дочернем классе объект получает собственную реализацию алгоритма.
    Пример задачи: сделать получение цен покупки зерновых культур (пшеница, рожь, ячмень и т.д.) с сайтов и API скупщиков (экспортёров, переработчиков).
  • ПОСЕТИТЕЛЬ (VISITOR)
    Предлагает схему, в которой объект-посетитель получает доступ к целевому объекту для выполнения различных обработок и действий. Это позволяет, не меняя класс целевого объекта, выполнять над ним различные операции, которые логически не имеют к нему прямого отношения.
    Пример задачи: для проекта дома вывести в таблицу список мебели и её стоимость.