Имеется поток запросов и переменное число "обработчиков" этих запросов. Необходимо эффективно обрабатывать запросы без жесткой привязки к их обработчикам, при этом запрос может быть обработан любым обработчиком.
Инкапсулирует элементы по обработке запросов внутри абстрактного "конвейера". Клиенты "кидают" свои запросы на вход этого конвейера.
Паттерн Chain of Responsibility связывает в цепочку объекты-получатели, а затем передает запрос-сообщение от одного объекта к другому до тех пор, пока не достигнет объекта, способного его обработать. Число и типы объектов-обработчиков заранее неизвестны, они могут настраиваться динамически. Механизм связывания в цепочку использует рекурсивную композицию, что позволяет использовать неограниченное число обработчиков.
Паттерн Chain of Responsibility упрощает взаимосвязи между объектами. Вместо хранения ссылок на всех кандидатов-получателей запроса, каждый отправитель хранит единственную ссылку на начало цепочки, а каждый получатель имеет единственную ссылку на своего преемника - последующий элемент в цепочке.
Паттерн Chain of Responsibility позволяет избежать привязки отправителя запроса к его получателю, давая шанс обработать запрос нескольким получателям. Банкомат использует Chain of Responsibility в механизме выдачи денег.
Используйте паттерн Command если
Система управляется событиями. При появлении такого события (запроса) необходимо выполнить определенную последовательность действий.
Необходимо параметризировать объекты выполняемым действием, ставить запросы в очередь или поддерживать операции отмены (undo) и повтора (redo) действий.
Нужен объектно-ориентированный аналог функции обратного вызова в процедурном программировании.
Пример событийно-управляемой системы – приложение с пользовательским интерфейсом. При выборе некоторого пункта меню пользователем вырабатывается запрос на выполнение определенного действия (например, открытия файла).
Паттерн Command преобразовывает запрос на выполнение действия в отдельный объект-команду. Такая инкапсуляция позволяет передавать эти действия другим функциям и объектам в качестве параметра, приказывая им выполнить запрошенную операцию. Команда – это объект, поэтому над ней допустимы любые операции, что и над объектом.
В паттерне Command может быть до трех участников:
Клиент, создающий экземпляр командного объекта.
Инициатор запроса, использующий командный объект.
Получатель запроса.
Результаты применения паттерна Command
Достоинства паттерна Command
Придает системе гибкость, отделяя инициатора запроса от его получателя.
Паттерн Interpreter (интерпетатор)
Назначение паттерна Interpreter
Для заданного языка определяет представление его грамматики, а также интерпретатор предложений этого языка.
Отображает проблемную область в язык, язык – в грамматику, а грамматику – в иерархии объектно-ориентированного проектирования.
Решаемая проблема
Пусть в некоторой, хорошо определенной области периодически случается некоторая проблема. Если эта область может быть описана некоторым “языком“, то проблема может быть легко решена с помощью “интерпретирующей машины“.
Обсуждение паттерна Interpreter
Паттерн Interpreter определяет грамматику простого языка для проблемной области, представляет грамматические правила в виде языковых предложений и интерпретирует их для решения задачи. Для представления каждого грамматического правила паттерн Interpreter использует отдельный класс. А так как грамматика, как правило, имеет иерархическую структуру, то иерархия наследования классов хорошо подходит для ее описания.
Паттерн Interpreter моделирует проблемную область с помощью рекурсивной грамматики. Каждое грамматическое правило может быть либо составным (правило ссылается на другие правила) либо терминальным (листовой узел в структуре ”дерево”).
Паттерн Intepreter определяет грамматическое представление для языка и интерпретатор для интерпретации грамматики. Музыканты являются примерами интерпретаторов. Тональность и продолжительность звуков могут быть описаны нотами. Такое представление является музыкальным языком. Музыканты, используя ноты, способны воспроизвести оригинальные частоту и длительность каждого представленного звука.
Паттерн Iterator (итератор, cursor, курсор)
Назначение паттерна Iterator
Предоставляет способ последовательного доступа ко всем элементам составного объекта, не раскрывая его внутреннего представления.
Абстракция в стандартных библиотеках C++ и Java, позволяющая разделить классы коллекций и алгоритмов.
Придает обходу коллекции "объектно-ориентированный статус".
Полиморфный обход.
Решаемая проблема
Вам необходим механизм "абстрактного" обхода различных структур данных так, что могут определяться алгоритмы, способные взаимодействовать со структурами прозрачно.
Обсуждение паттерна Iterator
Составной объект, такой как список, должен предоставлять способ доступа к его элементам без раскрытия своей внутренней структуры. Более того, иногда нужно перебирать элементы списка различными способами, в зависимости от конкретной задачи. Но вы, вероятно, не хотите раздувать интерфейс списка операциями для различных обходов, даже если они необходимы. Кроме того, иногда нужно иметь несколько активных обходов одного списка одновременно. Было бы хорошо иметь единый интерфейс для обхода разных типов составных объектов (т.е. полиморфная итерация).
Паттерн Iterator позволяет все это делать. Ключевая идея состоит в том, чтобы ответственность за доступ и обход переместить из составного объекта на объект Iterator, который будет определять стандартный протокол обхода.
У телевизоров прошлого поколения для смены ТВ-каналов использовался вращающийся переключатель. Каждой позиции на переключателе назначался свой канал. У современных телевизоров для смены каналов можно использовать кнопки "Далее" и "Назад". Когда телезритель нажимает кнопку "Далее", будет отображаться следующий настроенный канал. Телезритель всегда может запросить следующий канал, не зная его номера.
Паттерн Mediator определяет объект, инкапсулирующий взаимодействие множества объектов. Mediator делает систему слабо связанной, избавляя объекты от необходимости ссылаться друг на друга, что позволяет изменять взаимодействие между ними независимо.
Паттерн Mediator вводит посредника для развязывания множества взаимодействующих объектов.
Заменяет взаимодействие "все со всеми" взаимодействием "один со всеми".
Мы хотим спроектировать систему с повторно используемыми компонентами, однако существующие связи между этими компонентами можно охарактеризовать феноменом "спагетти-кода".
Паттерн Mediator определяет объект, управляющий набором взаимодействующих объектов. Слабая связанность достигается благодаря тому, что вместо непосредственного взаимодействия друг с другом коллеги общаются через объект-посредник. Башня управления полетами в аэропорту хорошо демонстрирует этот паттерн. Пилоты взлетающих или идущих на посадку самолетов в районе аэропорта общаются с башней вместо непосредственного общения друг с другом. Башня определяет, кто и в каком порядке будет садиться или взлетать. Важно отметить, что башня контролирует самолеты только в районе аэродрома, а не на протяжении всего полета.
Паттерн Memento (хранитель)
Назначение паттерна Memento
Не нарушая инкапсуляции, паттерн Memento получает и сохраняет за пределами объекта его внутреннее состояние так, чтобы позже можно было восстановить объект в таком же состоянии.
Является средством для инкапсуляции "контрольных точек" программы.
Паттерн Memento придает операциям "Отмена" (undo) или "Откат" (rollback) статус "полноценного объекта".
Решаемая проблема
Вам нужно восстановить объект обратно в прежнее состояние (те есть выполнить операции "Отмена" или "Откат").
Обсуждение паттерна Memento
Клиент запрашивает Memento (хранителя) у исходного объекта, когда ему необходимо сохранить состояние исходного объекта (установить контрольную точку). Исходный объект инициализирует Memento своим текущим состоянием. Клиент является "посыльным" за Memento, но только исходный объект может сохранять и извлекать информацию из Memento (Memento является "непрозрачным" для клиентов и других объектов). Если клиенту в дальнейшем нужно "откатить" состояние исходного объекта, он передает Memento обратно в исходный объект для его восстановления.
Реализовать возможность выполнения неограниченного числа операций "Отмена" (undo) и "Повтор" (redo) можно с помощью стека объектов Command и стека объектов Memento.
Паттерн проектирования Memento определяет трех различных участников:
Originator (хозяин) - объект, умеющий создавать хранителя, а также знающий, как восстановить свое внутреннее состояние из хранителя.
Caretaker (смотритель) - объект, который знает, почему и когда хозяин должен сохранять и восстанавливать себя.
Memento (хранитель) - "ящик на замке", который пишется и читается хозяином и за которым присматривает смотритель.
Паттерн Memento фиксирует и сохраняет за пределами объекта его внутреннее состояние так, чтобы позже этот объект можно было бы восстановить в таком же состоянии. Этот паттерн часто используется механиками-любителями для ремонта барабанных тормозов на своих автомобилях. Барабаны удаляются с обеих сторон, чтобы сделать видимыми правые и левые тормоза. При этом разбирается только одна сторона, другая же служит напоминанием (Memento) о том, как части тормозной системы тормозной системы собраны вместе. Только после того, как завершена работа с одной стороны, разбирается другая сторона. При этом в качестве Memento выступает уже первая сторона.
Паттерн Observer определяет зависимость "один-ко-многим" между объектами так, что при изменении состояния одного объекта все зависящие от него объекты уведомляются и обновляются автоматически.
Паттерн Observer инкапсулирует главный (независимый) компонент в абстракцию Subject и изменяемые (зависимые) компоненты в иерархию Observer.
Паттерн Observer определяет часть "View" в модели Model-View-Controller (MVC) .
Паттерн Observer находит широкое применение в системах пользовательского интерфейса, в которых данные и их представления ("виды") отделены друг от друга. При изменении данных должны быть изменены все представления этих данных (например, в виде таблицы, графика и диаграммы).
Имеется система, состоящая из множества взаимодействующих классов. При этом взаимодействующие объекты должны находиться в согласованных состояниях. Вы хотите избежать монолитности такой системы, сделав классы слабо связанными (или повторно используемыми).
Паттерн Observer определяет зависимость "один-ко-многим" между объектами так, что при изменении состояния одного объекта все зависящие от него объекты уведомляются и обновляются автоматически. Некоторые аукционы демонстрируют этот паттерн. Каждый участник имеет карточку с цифрами, которую он использует для обозначения предлагаемой цены (ставки). Ведущий аукциона (Subject) начинает торги и наблюдает, когда кто-нибудь поднимает карточку, предлагая новую более высокую цену. Ведущий принимает заявку, о чем тут же извещает всех участников аукциона (Observers).
Паттерн State (состояние)
Назначение паттерна State
Паттерн State позволяет объекту изменять свое поведение в зависимости от внутреннего состояния. Создается впечатление, что объект изменил свой класс.
Паттерн State является объектно-ориентированной реализацией конечного автомата.
Решаемая проблема
Поведение объекта зависит от его состояния и должно изменяться во время выполнения программы. Такую схему можно реализовать, применив множество условных операторов: на основе анализа текущего состояния объекта предпринимаются определенные действия. Однако при большом числе состояний условные операторы будут разбросаны по всему коду, и такую программу будет трудно поддерживать.
Пример паттерна State
Паттерн State позволяет объекту изменять свое поведение в зависимости от внутреннего состояния. Похожая картина может наблюдаться в работе торгового автомата. Автоматы могут иметь различные состояния в зависимости от наличия товаров, суммы полученных монет, возможности размена денег и т.д. После того как покупатель выбрал и оплатил товар, возможны следующие ситуации (состояния):
Выдать покупателю товар, выдавать сдачу не требуется.
Выдать покупателю товар и сдачу.
Покупатель товар не получит из-за отсутствия достаточной суммы денег.
Покупатель товар не получит из-за его отсутствия.
Существуют системы, поведение которых может определяться согласно одному алгоритму из некоторого семейства. Все алгоритмы этого семейства являются родственными: предназначены для решения общих задач, имеют одинаковый интерфейс для использования и отличаются только реализацией (поведением). Пользователь, предварительно настроив программу на нужный алгоритм (выбрав стратегию), получает ожидаемый результат. Как пример, - приложение, предназначенное для компрессии файлов использует один из доступных алгоритмов: zip, arj или rar.
Результаты применения паттерна Strategy
Достоинства паттерна Strategy
Систему проще поддерживать и модифицировать, так как семейство алгоритмов перенесено в отдельную иерархию классов.
Паттерн Strategy предоставляет возможность замены одного алгоритма другим в процессе выполнения программы.
Паттерн Strategy позволяет скрыть детали реализации алгоритмов от клиента.
Недостатки паттерна Strategy
Для правильной настройки системы пользователь должен знать об особенностях всех алгоритмов.
Число классов в системе, построенной с применением паттерна Strategy, возрастает.
Паттерн Template Method (шаблонный метод)
Назначение паттерна Template Method
Паттерн Template Method определяет основу алгоритма и позволяет подклассам изменить некоторые шаги этого алгоритма без изменения его общей структуры.
Базовый класс определяет шаги алгоритма с помощью абстрактных операций, а производные классы их реализуют.
Решаемая проблема
Имеются два разных, но в тоже время очень похожих компонента. Вы хотите внести изменения в оба компонента, избежав дублирования кода.
Пример паттерна Template Method
Паттерн Template Method определяет основу алгоритма и позволяет подклассам изменить некоторые шаги этого алгоритма без изменения его общей структуры. Строители зданий используют шаблонный метод при проектировании новых домов. Здесь могут использоваться уже существующие типовые планы, в которых модифицируются только отдельные части.
Паттерн Visitor (посетитель)
Назначение паттерна Visitor
Паттерн Visitor определяет операцию, выполняемую на каждом элементе из некоторой структуры. Позволяет, не изменяя классы этих объектов, добавлять в них новые операции.
Является классической техникой для восстановления потерянной информации о типе.
Паттерн Visitor позволяет выполнить нужные действия в зависимости от типов двух объектов.
Предоставляет механизм двойной диспетчеризации.