Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Билеты ООП / 15. Паттерн Strategy (стратегия)

.docx
Скачиваний:
82
Добавлен:
16.03.2016
Размер:
83.62 Кб
Скачать

Стратегия (англ. Strategy) — поведенческий шаблон проектирования, предназначенный для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости. Это позволяет выбирать алгоритм путем определения соответствующего класса. Шаблон Strategy позволяет менять выбранный алгоритм независимо от объектов-клиентов, которые его используют.

Задача

По типу клиента (или по типу обрабатываемых данных) выбрать подходящий алгоритм, который следует применить. Если используется правило, которое не подвержено изменениям, нет необходимости обращаться к шаблону «стратегия».

Мотивы

  • Программа должна обеспечивать различные варианты алгоритма или поведения

  • Нужно изменять поведение каждого экземпляра класса

  • Необходимо изменять поведение объектов на стадии выполнения

  • Введение интерфейса позволяет классам-клиентам ничего не знать о классах, реализующих этот интерфейс и инкапсулирующих в себе конкретные алгоритмы

Способ решения

Отделение процедуры выбора алгоритма от его реализации. Это позволяет сделать выбор на основании контекста.

Участники

  • Класс Strategy определяет, как будут использоваться различные алгоритмы.

  • Конкретные классы ConcreteStrategy реализуют эти различные алгоритмы.

  • Класс Context использует конкретные классы ConcreteStrategy посредством ссылки на конкретный тип абстрактного класса Strategy. Классы Strategy и Context взаимодействуют с целью реализации выбранного алгоритма (в некоторых случаях классу Strategy требуется посылать запросы классу Context). Класс Context пересылает классу Strategy запрос, поступивший от его класса-клиента.

Следствия

  • Шаблон Strategy определяет семейство алгоритмов.

  • Это позволяет отказаться от использования переключателей и/или условных операторов.

  • Вызов всех алгоритмов должен осуществляться стандартным образом (все они должны иметь одинаковый интерфейс).

Достоинства паттерна Strategy

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

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

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

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

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

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

Структура паттерна Strategy

\

UML-диаграмма классов паттерна Strategy

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

using System;

namespace DesignPatterns.Behavioral.Strategy

{

// Класс реализующий конкретную стратегию, должен наследовать этот интерфейс

// Класс контекста использует этот интерфейс для вызова конкретной стратегии

public interface IStrategy

{

void Algorithm();

}

// Первая конкретная реализация-стратегия.

public class ConcreteStrategy1 : IStrategy

{

public void Algorithm()

{

Console.WriteLine("Выполняется алгоритм стратегии 1.");

}

}

// Вторая конкретная реализация-стратегия.

// Реализаций может быть сколько угодно много.

public class ConcreteStrategy2 : IStrategy

{

public void Algorithm()

{

Console.WriteLine("Выполняется алгоритм стратегии 2.");

}

}

// Контекст, использующий стратегию для решения своей задачи.

public class Context

{

// Ссылка на интерфейс IStrategy

// позволяет автоматически переключаться между конкретными реализациями

// (другими словами, это выбор конкретной стратегии).

private IStrategy _strategy;

// Конструктор контекста.

// Инициализирует объект стратегией.

public Context(IStrategy strategy)

{

_strategy = strategy;

}

// Метод для установки стратегии.

// Служит для смены стратегии во время выполнения.

// В C# может быть реализован также как свойство записи.

public void SetStrategy(IStrategy strategy)

{

_strategy = strategy;

}

// Некоторая функциональность контекста, которая выбирает

//стратегию и использует её для решения своей задачи.

public void ExecuteOperation()

{

_strategy.Algorithm();

}

}

// Класс приложения.

// В данном примере выступает как клиент контекста.

public static class Program

{

// <summary>

// Точка входа в программу.

// </summary>

public static void Main()

{

// Создаём контекст и инициализируем его первой стратегией.

Context context = new Context(new ConcreteStrategy1());

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

context.ExecuteOperation();

// Заменяем в контексте первую стратегию второй.

context.SetStrategy(new ConcreteStrategy2());

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

context.ExecuteOperation();

}

}

}

Дополнительная информация

Назначение паттерна Strategy

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

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

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

  1. Реализация алгоритма жестко привязана к его подклассу, что затрудняет поддержку и расширение такой системы.

  2. Система, построенная на основе наследования, является статичной. Заменить один алгоритм на другой в ходе выполнения программы уже невозможно.

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

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

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