- •Лабораторная работа №4 Шаблоны проектирования
- •Теоретические сведения
- •Отношения между классами. На диаграммах классов языка uml
- •Суть паттерна
- •Решение
- •Адаптер объектов
- •Адаптер классов
- •Адаптер классов не нуждается во вложенном объекте, так как он может одновременно наследовать и часть существующего класса, и часть сервиса.
- •Фасад (Facade)
- •Концептуальный пример
- •Program.Cs:
- •Output.Txt: Результат выполнения
- •Изолирует клиентов от компонентов подсистемы Уменьшая тем самым число объектов, с которыми клиентам приходится иметь дело, упрощая работу с подсистемой.
- •Позволяет ослабить связанность между подсистемой и ее клиентами.
- •Фасад не исключает возможности приложениям напрямую обращаться к классам подсистемы, если это необходимо.
- •Заместитель (Proxy)
- •3. Локальный запуск сервиса (удалённый прокси). Когда настоящий сервисный объект находится на удалённом сервере.
- •Концептуальный пример
- •Декоратор (Decorator)
- •// Объект
- •} //Ptr2 выходит из области видимости, но объект не //освобождается, потому что есть ptr, который по-прежнему //ссылается на него } //ptr выходит из области видимости, и объект уничтожается
- •Пример на языке c#
- •Порождающие шаблоны Абстрактная фабрика (Abstract Factory)
- •1. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы.
- •3. Таким образом, еще раз - предоставляет интерфейс для создания семейств, связанных между собой, или зависимых объектов.
- •Клиент пользуется только интерфейсами, заданными в классах «Абстрактная фабрика» и «Абстрактный продукт».
- •Фабричный метод (Factory Method)
- •Void info() {
- •Void info() {
- •Void info() {
- •Int main()
- •Одиночка (Singleton) Суть паттерна
- •If(!p_instance)
- •Поведенческие шаблоны Стратегия (Strategy)
- •Стратегии построения пути.
- •Структура
- •Концептуальный пример
- •Program.Cs: Пример структуры паттерна
- •Output.Txt: Результат выполнения
- •Void useStrategy(void)
- •Void setStrategy(Strategy* o)
- •Int main(int /*argc*/, char* /*argv*/[])
- •Наблюдатель (Observer) Суть паттерна
- •Решение
- •Структура
- •Шаги реализации
- •Концептуальный пример
- •Program.Cs: Пример структуры паттерна
- •// Random.Next(…) - Метод, возвращает случайное целое число //в указанном диапазоне.
- •Output.Txt: Результат выполнения
- •Использование паттерна Observer
- •Команда (Command)
- •Структура
- •Output.Txt: Результат выполнения
- •Задания для лабораторной работы
Output.Txt: Результат выполнения
Client: Strategy is set to normal sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
a,b,c,d,e
Client: Strategy is set to reverse sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
e,d,c,b,a
Output.txt:
Клиент: Стратегия настроена на нормальную сортировку. Контекст: Сортировка данных с использованием стратегии (не знаю, как это будет делать)
a,b,c,d,e
Клиент: Стратегия настроена на обратную сортировку. Контекст: Сортировка данных с использованием стратегии (не знаю, как это будет делать)
e,d,c,b,a
Стратегия — поведенческий шаблон проектирования, предназначенный для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости.
Это позволяет выбирать алгоритм путем определения соответствующего класса.
Шаблон Strategy позволяет менять выбранный алгоритм независимо от объектов клиентов, которые его используют.
Проблема: по типу клиента (или по типу обрабатываемых данных) выбрать подходящий алгоритм, который следует применить.
Если используется правило, которое не подвержено изменениям, нет необходимости обращаться к шаблону «стратегия».
Решение: отделение процедуры выбора алгоритма от его реализации. Это позволяет сделать выбор на основании контекста.
- Класс Strategy определяет, как будут использоваться различные алгоритмы.
- Конкретные классы ConcreteStrategy реализуют эти различные алгоритмы.
- Класс Context использует конкретные классы ConcreteStrategy посредством ссылки на конкретный тип абстрактного класса Strategy.
- Классы Strategy и Context взаимодействуют с целью реализации выбранного алгоритма (в некоторых случаях классу Strategy требуется посылать запросы классу Context).
- Класс Context пересылает классу Strategy запрос, поступивший от его класса клиента.
- Этот паттерн инкапсулирует семейство алгоритмов, делая их взаимозаменяемыми.
Применять его целесообразно в следующих случаях:
• Имеются родственные классы, отличающиеся только поведением. Стратегия позволяет гибко конфигурировать класс, задавая одно из возможных поведений;
• Требуется иметь несколько разных вариантов алгоритма.
• Например, можно определить два варианта алгоритма, один из которых требует больше времени, а другой — больше памяти.
Кроме того, с помощью стратегии легко определить поведение класса по умолчанию.
Варианты алгоритмов могут быть реализованы в виде иерархии классов, что позволяет вычленить общую для всех классов функциональность.
Инкапсулированные алгоритмы можно затем применять в разных контекстах;
• В алгоритме хранятся данные, о которых клиент не должен «знать». Стратегия позволяет не раскрывать сложные, специфичные для алгоритма структуры данных;
• В классе определено много вариантов поведения, что представлено разветвленными условными операторами. В этом случае проще перенести код из ветвей в отдельные классы стратегий.
Структура паттерна приведена на рис.
Паттерн состоит из следующих классов:
• Strategy (стратегия) объявляет общий для всех поддерживаемых алгоритмов интерфейс.
• Класс Context пользуется этим интерфейсом для вызова конкретного алгоритма, определенного в классе ConcreteStrategy;
• ConcreteStrategy (конкретная стратегия) — наследник класса Strategy. Реализует алгоритм, использующий интерфейс, объявленный в классе Strategy;
• Context (контекст) конфигурируется объектом класса ConcreteStrategy. Хранит ссылку на объект класса Strategy и может определять интерфейс, который позволяет объекту Strategy получить доступ к данным контекста.
Таким образом, объект Context делегирует реализацию конкретного алгоритма поведения объекту Strategy, что дает возможность гибко изменять поведение объекта.
#include <iostream>
#include <string>
// Иерархия классов, определяющая алгоритмы сжатия файлов
{ class Compression
public:
virtual ~Compression() {}
virtual void compress( const string & file ) = 0;
};
class ZIP_Compression : public Compression
{
public:
void compress( const string & file ) {
cout << "ZIP compression" << endl;
}
};
class ARJ_Compression : public Compression
{
public:
void compress( const string & file ) {
cout << "ARJ compression" << endl;
}
};
class RAR_Compression : public Compression
{
public:
void compress( const string & file ) {
cout << "RAR compression" << endl;
}
};
// Класс для использования
class Compressor
{ public:
Compressor( Compression* comp): p(comp) {}
~Compressor() { delete p; }
void compress( const string & file ) {
p->compress( file);
}
private:
Compression* p;
};
int main()
{
Compressor* p = new Compressor( new ZIP_Compression);
p->compress( "file.txt");
delete p;
return 0;
}
Следствия
- Шаблон Strategy определяет семейство алгоритмов.
- Это позволяет отказаться от использования переключателей и/или условных операторов.
- Вызов всех алгоритмов должен осуществляться стандартным образом (все они должны иметь одинаковый интерфейс).
Реализация
- Класс, который использует алгоритм (Context), включает абстрактный класс (Strategy), обладающий абстрактным методом, определяющим способ вызова алгоритма.
- Каждый производный класс реализует один требуемый вариант алгоритма.
Замечание: метод вызова алгоритма не должен быть абстрактным, если требуется реализовать некоторое поведение, принимаемое по умолчанию.
Полезные сведения
И Стратегия, и Декоратор могут применяться для изменения поведения конкретных классов.
Достоинство Стратегии в том, что интерфейс кастомизации (адаптация под запрос) не совпадает с публичным интерфейсом и может быть куда более удобным.
Недостаток в том, что для использования стратегии необходимо изначально проектировать класс с возможностью регистрации стратегий.
Использование
- Архитектура Microsoft WDF (Windows Driver Frameworks — набор программных инструментов, облегчающих разработку драйверов устройств для Windows) основана на этом паттерне.
- Библиотека ATL (Active Template Library — набор шаблонных классов языка C++, разработанных компанией Microsoft для упрощения написания COM-компонентов.)
В то же время ATL позволяет создавать небольшие по размеру элементы управления, которые не требуют поддержки библиотек. Библиотека содержит в себе набор классов threading model, которые являются Cтратегиями (различными реализациями Lock/Unlock (зафиксировать/отменить /блокировать /разблокировать), которые потом используются основными классами системы).
При этом в этих стратегиях используется статический полиморфизм через параметр шаблона, а не динамический полиморфизм через виртуальные методы.
#include <iostream>
class Strategy
{ public:
virtual ~Strategy() {}
virtual void use(void) = 0;
};
class Strategy_1: public Strategy
{
public:
void use(void){ std::cout << "Strategy_1" << std::endl; };
};
class Strategy_2: public Strategy
{
public:
void use(void){ std::cout << "Strategy_2" << std::endl; };
};
class Strategy_3: public Strategy
{
public:
void use(void){ std::cout << "Strategy_3" << std::endl; };
};
class Context
{ protected:
Strategy* operation;
public:
virtual ~Context() {}
virtual void useStrategy(void) = 0;
virtual void setStrategy(Strategy* v) = 0;
};
class Client: public Context
{ public:
