Паттерн Strategy (стратегия)
Назначение паттерна Strategy
Существуют системы, поведение которых может определяться согласно одному алгоритму из некоторого семейства. Все алгоритмы этого семейства являются родственными: предназначены для решения общих задач, имеют одинаковый интерфейс для использования и отличаются только реализацией (поведением). Пользователь, предварительно настроив программу на нужный алгоритм (выбрав стратегию), получает ожидаемый результат. Как пример, - приложение, предназначенное для компрессии файлов использует один из доступных алгоритмов: zip, arj или rar.
Объектно-ориентированный дизайн такой программы может быть построен на идее использования полиморфизма. В результате получаем набор родственных классов с общим интерфейсом и различными реализациями алгоритмов.
Представленному подходу свойственны следующие недостатки:
- Реализация алгоритма жестко привязана к его подклассу, что затрудняет поддержку и расширение такой системы.
- Система, построенная на основе наследования, является статичной. Заменить один алгоритм на другой в ходе выполнения программы уже невозможно.
Применение паттерна Strategy позволяет устранить указанные недостатки.
Описание паттерна Strategy
Паттерн Strategy переносит в отдельную иерархию классов все детали, связанные с реализацией алгоритмов. Для случая программы сжатия файлов абстрактный базовый класс Compression этой иерархии объявляет интерфейс, общий для всех алгоритмов и используемый классом Compressor. Подклассы ZIP_Compression, ARJ_Compression и RAR_Compression его реализуют в соответствии с тем или иным алгоритмом. Класс Compressor содержит указатель на объект абстрактного типа Compression и предназначен для переадресации пользовательских запросов конкретному алгоритму. Для замены одного алгоритма другим достаточно перенастроить этот указатель на объект нужного типа.
Структура паттерна Strategy
UML-диаграмма классов паттерна Strategy
Реализация паттерна Strategy
Приведем реализацию приложения для сжатия файлов, спроектированного с применением паттерна 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
Достоинства паттерна Strategy
- Систему проще поддерживать и модифицировать, так как семейство алгоритмов перенесено в отдельную иерархию классов.
- Паттерн Strategy предоставляет возможность замены одного алгоритма другим в процессе выполнения программы.
- Паттерн Strategy позволяет скрыть детали реализации алгоритмов от клиента.
Недостатки паттерна Strategy
- Для правильной настройки системы пользователь должен знать об особенностях всех алгоритмов.
- Число классов в системе, построенной с применением паттерна Strategy, возрастает.