Паттерн Strategy

Название и классификация паттерна

Стратегия — паттерн поведения объектов.

Назначение

Определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми.

Стратегия позволяет изменять алгоритмы независимо от клиентов, которые ими пользуются.

Существуют системы, поведение которых может определяться согласно одному алгоритму из некоторого семейства. Все алгоритмы этого семейства являются родственными: предназначены для решения общих задач, имеют одинаковый интерфейс для использования и отличаются только реализацией (поведением). Пользователь, предварительно настроив программу на нужный алгоритм (выбрав стратегию), получает ожидаемый результат. Как пример — приложение, предназначенное для компрессии файлов, использует один из доступных алгоритмов: zip, arj или гаг.

Объектно-ориентированный дизайн такой программы может быть построен на идее использования полиморфизма. В результате получаем набор родственных классов с общим интерфейсом и различными реализациями алгоритмов (рис. 72).

Набор родственных классов с общим интерфейсом

Рис. 72. Набор родственных классов с общим интерфейсом

Но представленному подходу свойственны следующие недостатки:

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

Применение паттерна Strategy позволяет устранить указанные недостатки.

Описание паттерна Strategy

Паттерн Strategy переносит в отдельную иерархию классов все детали, связанные с реализацией алгоритмов. Для случая программы сжатия файлов абстрактный базовый класс Compression этой иерархии объявляет интерфейс, общий для всех алгоритмов и используемый классом Compressor. Подклассы ZIPCompression, ARJComp-ression и RAR_Compression его реализуют в соответствии с тем или иным алгоритмом. Класс Compressor содержит указатель на объект абстрактного типа Compression и предназначен для переадресации пользовательских запросов конкретному алгоритму. Для замены одного алгоритма другим достаточно перенастроить этот указатель на объект нужного типа.

и М Ь-диаграмма реализации программы сжатия файлов с помощью

Рис. 73. и М Ь-диаграмма реализации программы сжатия файлов с помощью

паттерна Стратегия

UML-диаграмма классов паттерна Strategy Структура паттерна Стратегия показана на рис. 74.

UML-диаграмма паттерна Стратегия

Рис. 74. UML-диаграмма паттерна Стратегия

Участники

Strategy (Compression) — стратегия: объявляет общий для всех поддерживаемых алгоритмов интерфейс. Класс Context пользуется этим интерфейсом для вызова конкретного алгоритма, определенного в классе Concrete Strategy.

ConcreteStrategy (ZIPCompression, ARJCompression, RAR_ Compression) — конкретная Стратегия: реализует алгоритм, использующий интерфейс, объявленный в классе Strategy.

Context (Comporessor) — контекст:

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

Отношения

Классы Strategy и Context взаимодействуют для реализации выбранного алгоритма. Контекст может передать Стратегии все необходимые алгоритму данные в момент его вызова. Вместо этого контекст может позволить обращаться к своим операциям в нужные моменты, передав ссылку на самого себя операциям класса Strategy.

Контекст переадресует запросы своих клиентов объекту-Стратегии. Обычно клиент создает объект ConcreteStrategy и передает его контексту, после чего клиент «общается» исключительно с контекстом. Часто в распоряжении клиента находится несколько классов ConcreteStrategy, которые он может выбирать.

Достоинства и недостатки

Семейства родственных алгоритмов. Иерархия классов Strategy определяет семейство алгоритмов или поведений, которые можно повторно использовать в разных контекстах. Наследование позволяет вычленить общую для всех алгоритмов функциональность.

Альтернатива порождению подклассов. Можно напрямую породить от Context подклассы с различными поведениями. Но при этом поведение жестко «зашивается» в класс Context, что затрудняет понимание, сопровождение и расширение контекста. Кроме того, заменить алгоритм динамически уже не удастся. В результате вы получите множество родственных классов, отличающихся только алгоритмом или поведением. Инкапсуляции алгоритма в отдельный класс Strategy позволяют изменять его независимо от контекста.

С помощью Стратегий можно избавиться от условных операторов. Благодаря паттерну Стратегия удается отказаться от условных операторов при выборе нужного поведения. Инкапсуляция же каждого поведения в отдельный класс Strategy решает эту проблему.

Реализация паттерна Strategy

Приведем реализацию приложения для сжатия файлов, спроектированного с применением паттерна Strategy.

#include

#include

// Иерархия классов, определяющая алгоритмы сжатия файлов

class Compression

{

public:

virtual ~Compression() {}

virtual void compress( const string & file ) = 0;

};

class ZIP_Compression : public Compression

{

public:

void compress( const string & file ) { co?t << "ZIP compression" << endl;

}

};

class ARJ_Compression : public Compression

{

public:

void compress( const string & file ) { co?t << "ARJ compression" << endl;

}

};

class RAR_Compression : public Compression

{

public:

void compresse const string & file ) { co?t << "RAR compression" << endl;

}

};

// Класс для использования class Compressor {

public:

Compressor( Compression* comp): p(comp) {} ~Compressor() { delete p;} void compresse 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

Систему проще поддерживать и модифицировать, так как семейство алгоритмов перенесено в отдельную иерархию классов.

Паттерн Strategy предоставляет возможность замены одного алгоритма другим в процессе выполнения программы.

Паттерн Strategy позволяет скрыть детали реализации алгоритмов от клиента.

Недостатки паттерна Strategy

Для правильной настройки системы пользователь должен знать об особенностях всех алгоритмов.

Число классов в системе, построенной с применением паттерна Strategy, возрастает.

Родственные паттерны

Приспособленец: в ряде случаев объекты-стратегии могут быть реализованы как Приспособленцы.

 
< Пред   СОДЕРЖАНИЕ     След >