Достоинства паттерна Singleton
Класс сам контролирует процесс создания единственного экземпляра.
Паттерн легко адаптировать для создания нужного числа экземпляров.
Возможность создания объектов классов, производных от Singleton.
Недостатки паттерна Singleton
В случае использования нескольких взаимозависимых одиночек их реализация может резко усложниться.
Паттерн Adapter (адаптер, wrapper, обертка)
Назначение паттерна Adapter
Часто в новом программном проекте не удается повторно использовать уже существующий код. Например, имеющиеся классы могут обладать нужной функциональностью, но иметь при этом несовместимые интерфейсы. В таких случаях следует использовать паттерн Adapter (адаптер).
Паттерн Adapter, представляющий собой программную обертку над существующими классами, преобразует их интерфейсы к виду, пригодному для последующего использования.
Рассмотрим простой пример, когда следует применять паттерн Adapter. Пусть мы разрабатываем систему климат-контроля, предназначенной для автоматического поддержания температуры окружающего пространства в заданных пределах. Важным компонентом такой системы является температурный датчик, с помощью которого измеряют температуру окружающей среды для последующего анализа. Для этого датчика уже имеется готовое программное обеспечение от сторонних разработчиков, представляющее собой некоторый класс с соответствующим интерфейсом. Однако использовать этот класс непосредственно не удастся, так как показания датчика снимаются в градусах Фаренгейта. Нужен адаптер, преобразующий температуру в шкалу Цельсия.
Пусть класс, интерфейс которого нужно адаптировать к нужному виду, имеет имя Adaptee. Для решения задачи преобразования его интерфейса паттерн Adapter вводит следующую иерархию классов:
Виртуальный базовый класс Target. Здесь объявляется пользовательский интерфейс подходящего вида. Только этот интерфейс доступен для пользователя.
Производный класс Adapter, реализующий интерфейс Target. В этом классе также имеется указатель или ссылка на экземпляр Adaptee. Паттерн Adapter использует этот указатель для перенаправления клиентских вызовов в Adaptee. Так как интерфейсы Adaptee и Target несовместимы между собой, то эти вызовы обычно требуют преобразования.
UML-диаграмма классов паттерна Adapter
Результаты применения паттерна Adapter
Достоинства паттерна Adapter
Паттерн Adapter позволяет повторно использовать уже имеющийся код, адаптируя его несовместимый интерфейс к виду, пригодному для использования.
Недостатки паттерна Adapter
Задача преобразования интерфейсов может оказаться непростой в случае, если клиентские вызовы и (или) передаваемые параметры не имеют функционального соответствия в адаптируемом объекте.
Паттерн Bridge (мост, идиома "Handle/Body")
Назначение паттерна Bridge
В системе могут существовать классы, отношения между которыми строятся в соответствии со следующей объектно-ориентированной иерархией: абстрактный базовый класс объявляет интерфейс, а конкретные подклассы реализуют его нужным образом. Такой подход является стандартным в ООП, однако, ему свойственны следующие недостатки:
Система, построенная на основе наследования, является статичной. Реализация жестко привязана к интерфейсу. Изменить реализацию объекта некоторого типа в процессе выполнения программы уже невозможно.
Система становится трудно поддерживаемой, если число родственных производных классов становится большим.
Описание паттерна Bridge
Паттерн Bridge разделяет абстракцию и реализацию на две отдельные иерархии классов так, что их можно изменять независимо друг от друга.
Результаты применения паттерна Bridge
Достоинства паттерна Bridge
Проще расширять систему новыми типами за счет сокращения общего числа родственных подклассов.
Возможность динамического изменения реализации в процессе выполнения программы.
Паттерн Bridge полностью скрывает реализацию от клиента. В случае модификации реализации пользовательский код не требует перекомпиляции.
Паттерн Composite (компоновщик)
Назначение паттерна Composite
Используйте паттерн Composite если:
Необходимо объединять группы схожих объектов и управлять ими.
Объекты могут быть как примитивными (элементарными), так и составными (сложными). Составной объект может включать в себя коллекции других объектов, образуя сложные древовидные структуры. Пример: директория файловой системы состоит из элементов, каждый их которых также может быть директорией.
Код клиента работает с примитивными и составными объектами единообразно.
Описание паттерна Composite
Управление группами объектов может быть непростой задачей, особенно, если эти объекты содержат собственные объекты.
Результаты применения паттерна Composite
Достоинства паттерна Composite
В систему легко добавлять новые примитивные или составные объекты, так как паттерн Composite использует общий базовый класс Component.
Код клиента имеет простую структуру – примитивные и составные объекты обрабатываются одинаковым образом.
Паттерн Composite позволяет легко обойти все узлы древовидной структуры
Недостатки паттерна Composite
Неудобно осуществить запрет на добавление в составной объект Composite объектов определенных типов. Так, например, в состав римской армии не могут входить боевые слоны.
Паттерн Decorator (декоратор, wrapper, обертка)
Назначение паттерна Decorator
Паттерн Decorator динамически добавляет новые обязанности объекту. Декораторы являются гибкой альтернативой порождению подклассов для расширения функциональности.
Рекурсивно декорирует основной объект.
Паттерн Decorator использует схему "обертываем подарок, кладем его в коробку, обертываем коробку".
Решаемая проблема
Вы хотите добавить новые обязанности в поведении или состоянии отдельных объектов во время выполнения программы. Использование наследования не представляется возможным, поскольку это решение статическое и распространяется целиком на весь класс.
Пример паттерна Decorator
Паттерн Decorator динамически добавляет новые обязанности объекту. Украшения для новогодней елки являются примерами декораторов. Огни, гирлянды, игрушки и т.д. вешают на елку для придания ей праздничного вида. Украшения не меняют саму елку, а только делают ее новогодней.
Хотя картины можно повесить на стену и без рамок, рамки часто добавляются для придания нового стиля.
Паттерн Facade (фасад)
Назначение паттерна Facade
Паттерн Facade предоставляет унифицированный интерфейс вместо набора интерфейсов некоторой подсистемы. Facade определяет интерфейс более высокого уровня, упрощающий использование подсистемы.
Паттерн Facade "обертывает" сложную подсистему более простым интерфейсом.
Решаемая проблема
Клиенты хотят получить упрощенный интерфейс к общей функциональности сложной подсистемы.
Обсуждение паттерна Facade
Паттерн Facade инкапсулирует сложную подсистему в единственный интерфейсный объект. Это позволяет сократить время изучения подсистемы, а также способствует уменьшению степени связанности между подсистемой и потенциально большим количеством клиентов. С другой стороны, если фасад является единственной точкой доступа к подсистеме, то он будет ограничивать возможности, которые могут понадобиться "продвинутым" пользователям.
Объект Facade, реализующий функции посредника, должен оставаться довольно простым и не быть всезнающим "оракулом".
Клиенты общаются с подсистемой через Facade. При получении запроса от клиента объект Facade переадресует его нужному компоненту подсистемы. Для клиентов компоненты подсистемы остаются "тайной, покрытой мраком".
Паттерн Facade определяет унифицированный высокоуровневый интерфейс к подсистеме, что упрощает ее использование. Покупатели сталкиваются с фасадом при заказе каталожных товаров по телефону. Покупатель звонит в службу поддержки клиентов и перечисляет товары, которые хочет приобрести. Представитель службы выступает в качестве "фасада", обеспечивая интерфейс к отделу исполнения заказов, отделу продаж и службе доставки.
Паттерн Flyweight (приспособленец)
Назначение паттерна Flyweight
Паттерн Flyweight использует разделение для эффективной поддержки большого числа мелких объектов.
Решаемая проблема
Проектирование системы из объектов самого низкого уровня обеспечивает оптимальную гибкость, но может быть неприемлемо "дорогим" решением с точки зрения производительности и расхода памяти.
Обсуждение паттерна Flyweight
Паттерн Flyweight описывает, как совместно разделять очень мелкие объекты без чрезмерно высоких издержек. Каждый объект-приспособленец имеет две части: внутреннее и внешнее состояния. Внутреннее состояние хранится (разделяется) в приспособленце и состоит из информации, не зависящей от его контекста. Внешнее состояние хранится или вычисляется объектами-клиентами и передается приспособленцу при вызове его методов.
Паттерн Proxy (заместитель, surrogate, суррогат)
Назначение паттерна Proxy
Паттерн Proxy является суррогатом или замеcтителем другого объекта и контролирует доступ к нему.
Предоставляя дополнительный уровень косвенности при доступе к объекту, может применяться для поддержки распределенного, управляемого или интеллектуального доступа.
Являясь "оберткой" реального компонента, защищает его от излишней сложности.
Решаемая проблема
Вам нужно управлять ресурсоемкими объектами. Вы не хотите создавать экземпляры таких объектов до момента их реального использования.
Обсуждение паттерна Proxy
Суррогат или заместитель это объект, интерфейс которого идентичен интерфейсу реального объекта. При первом запросе клиента заместитель создает реальный объект, сохраняет его адрес и затем отправляет запрос этому реальному объекту. Все последующие запросы просто переадресуются инкапсулированному реальному объекту.
Существует четыре ситуации, когда можно использовать паттерн Proxy:
Виртуальный proxy является заместителем объектов, создание которых обходится дорого. Реальный объект создается только при первом запросе/доступе клиента к объекту.
Удаленный proxy предоставляет локального представителя для объекта, который находится в другом адресном пространстве ("заглушки" в RPC и CORBA).
Защитный proxy контролирует доступ к основному объекту. "Суррогатный" объект предоставляет доступ к реальному объекту, только вызывающий объект имеет соответствующие права.
Интеллектуальный proxy выполняет дополнительные действия при доступе к объекту.
Вот типичные области применения интеллектуальных proxy:
Подсчет числа ссылок на реальный объект. При отсутствии ссылок память под объект автоматически освобождается (известен также как интеллектуальный указатель или smart pointer).
Загрузка объекта в память при первом обращении к нему.
Установка запрета на изменение реального объекта при обращении к нему других объектов.
Структура паттерна Proxy
Заместитель Proxy и реальный объект RealSubject имеют одинаковые интерфейсы класса Subject, поэтому заместитель может использоваться "прозрачно" для клиента вместо реального объекта.
UML-диаграмма классов паттерна Proxy
Пример паттерна Proxy
Паттерн Proxy для доступа к реальному объекту использует его суррогат или заместитель. Банковский чек является заместителем денежных средств на счете. Чек может быть использован вместо наличных денег для совершения покупок и, в конечном счете, контролирует доступ к наличным деньгам на счете чекодателя.
Паттерн Chain of Responsibility (цепочка обязанностей)
Назначение паттерна Chain of Responsibility
Паттерн Chain of Responsibility позволяет избежать жесткой зависимости отправителя запроса от его получателя, при этом запрос может быть обработан несколькими объектами. Объекты-получатели связываются в цепочку. Запрос передается по этой цепочке, пока не будет обработан.
Вводит конвейерную обработку для запроса с множеством возможных обработчиков.
Объектно-ориентированный связанный список с рекурсивным обходом.