Шаблоны проектирования, используемые в ООП

Шаблоны проектирования, используемые в ООП

UniLecs

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

И рассмотрим следующие типы паттернов:


Фасад

Фасад — это структурный паттерн проектирования, который предоставляет простой интерфейс к сложной системе классов, библиотеке или фреймворку.

Фасад полезен, если вы используете какую-то сложную библиотеку со множеством подвижных частей, но вам нужна только часть её возможностей.

Например, программа, заливающая фотографии в сеть, может использовать профессиональную различные алгоритмы сжатия. Но для клиентского кода этой программы нужен простой метод UploadPhoto(file). Это и есть пример использования паттерна Фасад.

Плюсы:

  • Изолирует клиентов от компонентов сложной подсистемы

Минусы

Божественный объект (англ. God object) — антипаттерн объектно-ориентированного программирования, описывающий объект, который хранит в себе «слишком много» или делает «слишком много».


Заместитель (Proxy)

Заместитель — структурный шаблон проектирования, при котором общение с каким-то объектом контролирует другой объект-заместитель (прокси). Эти объекты перехватывают вызовы к оригинальному объекту, позволяя сделать что-то до или после передачи вызова оригиналу.

Шаблон Заместитель (Proxy) может применяться в случаях работы с сетевым соединением, с огромным объектом в памяти (или на диске) или с любым другим ресурсом, который сложно или тяжело копировать. Хорошо известный пример применения — объект, подсчитывающий число ссылок.

Плюсы:

  • Позволяет контролировать сервисный объект незаметно для клиента.
  • Может работать, даже если сервисный объект ещё не создан.
  • Может контролировать жизненный цикл служебного объекта.

Минусы:

  • Усложняет код программы из-за введения дополнительных классов.
  • Увеличивает время отклика от сервиса.


Фабричный метод

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

Например, вы создаёте программу управления перевозками. Сперва вы рассчитываете перевозить товары только на автомобилях. Поэтому весь ваш код работает с объектами класса Грузовик. Но что если вы хотите добавить другой вид транспорта, например, поезда. 

Паттерн Фабричный метод предлагает создавать объекты не напрямую, используя оператор new, а через вызов особого фабричного метода. Например, классы Грузовик и Поезд реализуют интерфейс Транспорт с методом доставить. Для клиента фабричного метода нет разницы между этими объектами, так как он будет трактовать их как некий абстрактный Транспорт. Для него будет важно, чтобы объект имел метод доставить, а как конкретно он работает — не важно.

Плюсы:

  • Избавляет класс от привязки к конкретным классам продуктов.
  • Выделяет код производства продуктов в одно место, упрощая поддержку кода.
  • Упрощает добавление новых продуктов в программу.
  • Реализует принцип открытости/закрытости.

Минусы:

  • Может привести к созданию больших параллельных иерархий классов, так как для каждого класса продукта надо создать свой подкласс создателя.


Абстрактная фабрика

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

Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы (например, для оконного интерфейса он может создавать окна и кнопки). Затем пишутся классы, реализующие этот интерфейс.

Плюсы:

  • Гарантирует сочетаемость создаваемых продуктов.
  • Избавляет клиентский код от привязки к конкретным классам продуктов.
  • Выделяет код производства продуктов в одно место, упрощая поддержку кода.
  • Упрощает добавление новых продуктов в программу.

Минусы:

  • Усложняет код программы из-за введения множества дополнительных классов.
  • Требует наличия всех типов продуктов в каждой вариации.


Декоратор

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

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

Плюсы:

  • Большая гибкость, чем у наследования.
  • Позволяет добавлять обязанности на лету.
  • Можно добавлять несколько новых обязанностей сразу.
  • Позволяет иметь несколько мелких объектов вместо одного объекта на все случаи жизни.

Минусы:

  • Трудно конфигурировать многократно обёрнутые объекты.
  • Обилие крошечных классов.


Наблюдатель

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

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

Шаблон «наблюдатель» применяется в тех случаях, когда система обладает следующими свойствами:

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

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

Плюсы:

  • Издатели не зависят от конкретных классов подписчиков и наоборот.
  • Вы можете подписывать и отписывать получателей на лету.
  • Реализует принцип открытости/закрытости.

Минусы:

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


Адаптер

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

Типичным примером использования шаблона Адаптер можно назвать создание классов, приводящих к единому интерфейсу функции языка обеспечивающие доступ к различным СУБД.

Плюсы:

  • Отделяет и скрывает от клиента подробности преобразования различных интерфейсов.

Минусы: 

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


Шаблонный метод

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

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

Применяется в следующих случаях:

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

Плюсы:

  • Облегчает повторное использование кода.

Минусы:

  • Вы жёстко ограничены скелетом существующего алгоритма.
  • Вы можете нарушить принцип подстановки Барбары Лисков, изменяя базовое поведение одного из шагов алгоритма через подкласс.
  • С ростом количества шагов шаблонный метод становится слишком сложно поддерживать.


Синглтон

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

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

  • Гарантирует наличие единственного экземпляра класса. Чаще всего это полезно для доступа к какому-то общему ресурсу, например, базе данных.
  • Предоставляет глобальную точку доступа. 

Плюсы:

  • Гарантирует наличие единственного экземпляра класса.
  • Предоставляет к нему глобальную точку доступа.
  • Реализует отложенную инициализацию объекта-одиночки.

Минусы:

  • Нарушает принцип единственной ответственности класса.
  • Маскирует плохой дизайн.
  • Проблемы мультипоточности.
  • Требует постоянного создания Mock-объектов при юнит-тестировании.


P.S. Замечательные картинки для шаблонов были взяты из шпаргалки по шаблонам проектирования:

Report Page