Шаблоны проектирования
Димитров Вячеслав Михайлович, старший преподаватель кафедры ИМО, dimitrov@cs.petrsu.ru
Шаблоны проектирования.
- Идея была заимствована из архитектуры (профессор Кристофер Александр).
- 23 шаблона из книги 1995 г. Design Patterns — Elements of Reusable Object-Oriented Software.
Для чего полезно иметь представления о шаблонах.
- Проверенные решения.
- Стандартизация кода.
- Общий язык.
Группы шаблонов.
- Порождающие шаблоны - определяют процесс порождения объектов.
- Структурные шаблоны - как классы и объекты объединяются в более крупные структкры.
- Поведенческие шаблоны - определяют алгоритмы и взаимодействия между классами и объектами.
Порождающие шаблоны.
- Абстрактная фабрика (Abstract Factory)
- Строитель (Builder)
- Фабричный метод (Factory Method)
- Прототип (Prototype)
- Одиночка (Singleton)
Абстрактная фабрика (Abstract Factory).
- Создание семейства объектов без их спецификации.
- Система не должна зависеть от способа создания.
- Создаваемые объекты должны использоваться вместе и являются взаимосвязанными.
Абстрактная фабрика.
Строитель (Builder)
- Процесс создания объекта не должен зависеть от процесса создания его частей.
- Builder определяет интерфейс конструирования продукта по частям.
- Director управляет процессом создания, не зная, какой продукт будет создан в результате.
- ConcreteBuilder — конкретный строитель, который создает только известный ему объект класса Product.
Строитель (Builder)
Фабричный метод (Factory Method)
- Когда заранее неизвестно, объекты каких типов необходимо создавать.
- Когда система должна быть независимой от процесса создания новых объектов и расширяемой: в нее можно легко вводить новые классы, объекты которых система должна создавать.
- Когда создание новых объектов необходимо делегировать из базового класса классам наследникам.
Фабричный метод (Factory Method)
Прототип (Prototype)
- Клонирование объектов.
- Когда желательно избежать наследования создателя объекта.
- Когда клонирование объекта является более предпочтительным вариантом нежели его создание и инициализация с помощью конструктора.
- Когда создание копии объекта проще и быстрее, чем порождение его стандартным путем, используя операцию new и включая инициализацию полей.
Прототип (Prototype)
Одиночка (Singleton)
- У класса есть только один экземпляр.
- Глобальную точку доступа к классу.
- Аналог глобальной переменной.
Одиночка (Singleton)
Структурные шаблоны.
- Адаптер (Adapter)
- Мост (Bridge)
- Компоновщик (Composite)
- Декоратор (Decorator)
- Фасад (Facade)
- Приспособленец (Flyweight)
- Заместитель (Proxy)
Адаптер (Adapter)
- Когда необходимо использовать имеющийся класс, но его интерфейс не соответствует потребностям бизнесс логики.
- Когда надо использовать уже существующий класс совместно с другими классами, интерфейсы которых не совместимы.
- Target: представляет объекты, которые используются клиентом
- Client: использует объекты Target для реализации своих задач
- Adaptee: представляет адаптируемый класс, который мы хотели бы использовать у клиента вместо объектов Target
- Adapter: собственно адаптер, который позволяет работать с объектами Adaptee как с объектами Target.
Адаптер (Adapter)
Мост (Bridge)
- Отделяет абстракцию от реализации таким образом, чтобы и абстракцию, и реализацию можно было изменять независимо друг от друга.
- Когда надо избежать постоянной привязки абстракции к реализации.
- Когда наряду с реализацией надо изменять и абстракцию независимо друг от друга. То есть изменения в абстракции не должно привести к изменениям в реализации.
Мост (Bridge)
Компоновщик (Composite)
- Когда объекты должны быть реализованы в виде иерархической древовидной структуры
- Когда клиенты единообразно должны управлять как целыми объектами, так и их составными частями. То есть целое и его части должны реализовать один и тот же интерфейс
- Component: определяет интерфейс для всех компонентов в древовидной структуре
- Composite: представляет компонент, который может содержать другие компоненты и реализует механизм для их добавления и удаления
- Leaf: представляет отдельный компонент, который не может содержать другие компоненты
- Client: клиент, который использует компоненты
Компоновщик (Composite)
Декоратор (Decorator)
- Когда надо динамически добавлять к объекту новые функциональные возможности.
- Когда применение наследования неприемлемо.
Декоратор (Decorator)
- Component: абстрактный класс, который определяет интерфейс для наследуемых объектов.
- ConcreteComponent: конкретная реализация компонента, в которую с помощью декоратора добавляется новая функциональность.
- Decorator: собственно декоратор, реализуется в виде абстрактного класса и имеет тот же базовый класс, что и декорируемые объекты. Поэтому базовый класс Component должен быть по возможности легким и определять только базовый интерфейс.
Декоратор (Decorator)
Фасад (Facade)
- Когда имеется сложная система, и необходимо упростить с ней работу. Фасад позволит определить одну точку взаимодействия между клиентом и системой.
- Когда надо уменьшить количество зависимостей между клиентом и сложной системой. Фасадные объекты позволяют отделить, изолировать компоненты системы от клиента и развивать и работать с ними независимо.
- Когда нужно определить подсистемы компонентов в сложной системе. Создание фасадов для компонентов каждой отдельной подсистемы позволит упростить взаимодействие между ними и повысить их независимость друг от друга.
Фасад (Facade)
- Знает, какие классы подсистемы отвечают за запрос.
- Делегирует запросы клиентов соответствующим объектам подсистем.
- Реализовывают функционал подсистемы
- Обрабатывают методы, назначенные объектом Facade.
- Не знают о фасаде и не ссылаются на него.
Фасад (Facade)
Приспособленец (Flyweight)
- Используется преимущественно для оптимизации работы с памятью.
- в приложении используется большое число очень схожих экземпляров заданного класса;
- (и) часть состояния объекта является контекстной и может быть легко вынесена во внешние структуры;
- (и) после вынесения части состояния, все экземпляры становятся одинаковыми и это дает возможность заменить их одним;
- (и) приложение не проверяет идентичность объектов, т.к. в этом случае все якобы самостоятельные экземпляры являются одним объектом.
Приспособленец (Flyweight)
Заместитель (Proxy)
- Удаленный заместитель — отвечает за кодирование запроса и его аргументов для работы с компонентом в другом адресном пространстве.
- Виртуальный заместитель — может кэшировать дополнительную информацию о реальном компоненте, чтобы отложить его создание.
- Защищающий заместитель — проверяет, имеет ли вызывающий объект необходимые для выполнения запроса прав.
Заместитель (Proxy)
Поведенческие шаблоны.
Определяют алгоритмы и взаимодействие между классами и объектами
- Цепочка обязанностей (Chain of responsibility)
- Команда (Command)
- Интерпретатор (Interpreter)
- Итератор (Iterator)
- Посредник (Mediator)
Поведенческие шаблоны.
- Хранитель (Memento)
- Наблюдатель (Observer)
- Состояние (State)
- Стратегия (Strategy)
- Шаблонный метод (Template method)
- Посетитель (Visitor)
Цепочка обязанностей (Chain of responsibility)
- Позволяет избежать привязки отправителя запроса к его получателю
- Когда имеется более одного объекта, который может обработать определенный запрос;
- Когда надо передать запрос на выполнение одному из нескольких объект, точно не определяя, какому именно объекту;
- Когда набор объектов задается динамически.
Цепочка обязанностей (Chain of responsibility)
Команда (Command)
- Когда необходимо обеспечить выполнение очереди запросов, а также их возможную отмену.
- Когда надо поддерживать логгирование изменений в результате запросов.
- Когда необходимо параметризировать объекты выполняемым действием, ставить запросы в очередь или поддерживать операции отмены (undo) и повтора (redo) действий.
Команда (Command)
Интерпретатор (Interpreter)
- Следует использовать когда вам необходимо интерпретировать запись в другом языке
Интерпретатор (Interpreter)
Итератор (Iterator)
- Представляет доступ ко всем элементам составного объекта, не раскрывая его внутреннего представления
- Когда необходимо осуществить обход объекта без раскрытия его внутренней структуры.
- Когда имеется набор составных объектов, и надо обеспечить единый интерфейс для их перебора.
- Когда необходимо предоставить несколько альтернативных вариантов перебора одного и того же объекта.
Итератор (Iterator)
Посредник (Mediator)
- Обеспечивает взаимодействие множества объектов без необходимости ссылаться друг на друга.
- Когда имеется множество взаимосвязаных объектов, связи между которыми сложны и запутаны.
- Когда необходимо повторно использовать объект, однако повторное использование затруднено в силу сильных связей с другими объектами.
Посредник (Mediator)
Хранитель (Memento)
- Позволяет выносить внутреннее состояние объекта за его пределы для последующего возможного восстановления объекта без нарушения принципа инкапсуляции.
- Когда нужно сохранить состояние объекта для возможного последующего восстановления.
- Когда сохранение состояния должно проходить без нарушения принципа инкапсуляции.
Хранитель (Memento)
Наблюдатель (Observer)
- определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом и автоматически обновляются.
- Когда система состоит из множества классов, объекты которых должны находиться в согласованных состояниях
- Когда общая схема взаимодействия объектов предполагает две стороны: одна рассылает сообщения и является главным, другая получает сообщения и реагирует на них. Отделение логики обеих сторон позволяет их рассматривать независимо и использовать отдельно друга от друга.
- Когда существует один объект, рассылающий сообщения, и множество подписчиков, которые получают сообщения. При этом точное число подписчиков заранее неизвестно и процессе работы программы может изменяться.
Наблюдатель (Observer)
Состояние (State)
- предполагает выделение базового класса или интерфейса для всех допустимых операций и наследника для каждого возможного состояния
- Когда поведение объекта должно зависеть от его состояния и может изменяться динамически во время выполнения
- Когда в коде методов объекта используются многочисленные условные конструкции, выбор которых зависит от текущего состояния объекта
Состояние (State)
Стратегия (Strategy)
- стратегия инкапсулирует определенное поведение с возможностью его подмены.
- Когда есть несколько схожих классов , которые отличаются поведением. Можно задать один основной класс, а разные варианты поведения вынести в отдельные классы и при необходимости их применять;
- Когда необходимо обеспечить выбор из нескольких вариантов решений, которые можно легко менять в зависимости от условий;
- Когда необходимо менять поведение классов и объектов на стадии выполнения программы;
- Когда класс, применяющий определенную функциональность, ничего не должен знать о ее реализации
Стратегия (Strategy)
Шаблонный метод (Template method)
- определяет основу алгоритма и позволяет подклассам переопределять некоторые шаги алгоритма, не изменяя его структуры в целом.
- Когда планируется, что в будущем подклассы должны будут переопределять различные этапы алгоритма без изменения его структуры
- Когда в классах, реализующим схожий алгоритм, происходит дублирование кода. Вынесение общего кода в шаблонный метод уменьшит его дублирование в подклассах.
Шаблонный метод (Template method)
Посетитель (Visitor)
- описывает операцию, выполняемую с каждым объектом из некоторой иерархии классов.
- Паттерн Посетитель определяет операцию, выполняемую на каждом элементе из некоторой структуры. Позволяет, не изменяя классы этих объектов, добавлять в них новые операции.
- Является классической техникой для восстановления потерянной информации о типе.
- Паттерн Посетитель позволяет выполнить нужные действия в зависимости от типов двух объектов.
- Предоставляет механизм двойной диспетчеризации.
Посетитель (Visitor)
Критика ООП.
- Изменчивое состояние.
- Не моделируют реальную предметную область.
- Функции и код вместе.
- Сложно тестировать (нужно создавать контекст).