Паттерн «Стратегия» (Strategy)
Назначение: определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Стратегия позволяет изменять алгоритмы независимо от клиентов, которые ими пользуются.
Другими словами: стратегия инкапсулирует определенное поведение с возможностью его подмены.
Когда использовать стратегию?
-
Когда есть несколько схожих классов , которые отличаются поведением. Можно задать один основной класс, а разные варианты поведения вынести в отдельные классы и при необходимости их применять;
-
Когда необходимо обеспечить выбор из нескольких вариантов решений, которые можно легко менять в зависимости от условий;
-
Когда необходимо менять поведение классов и объектов на стадии выполнения программы;
-
Когда класс, применяющий определенную функциональность, ничего не должен знать о ее реализации
Паттерн "стратегия" можно выразить на схеме UML таким образом:
Реализация схемы на языке C#
/// <summary>
/// The 'Strategy' abstract class
/// </summary>
public abstract class Strategy
{
public abstract void AlgorithmInterface();
}
/// <summary>
/// A 'ConcreteStrategy' class
/// </summary>
public class ConcreteStrategyA : Strategy
{
public override void AlgorithmInterface()
{
Console.WriteLine(
"Called ConcreteStrategyA.AlgorithmInterface()");
}
}
/// <summary>
/// A 'ConcreteStrategy' class
/// </summary>
public class ConcreteStrategyB : Strategy
{
public override void AlgorithmInterface()
{
Console.WriteLine(
"Called ConcreteStrategyB.AlgorithmInterface()");
}
}
/// <summary>
/// A 'ConcreteStrategy' class
/// </summary>
public class ConcreteStrategyC : Strategy
{
public override void AlgorithmInterface()
{
Console.WriteLine(
"Called ConcreteStrategyC.AlgorithmInterface()");
}
}
/// <summary>
/// The 'Context' class
/// </summary>
public class Context
{
private readonly Strategy _strategy;
// Constructor
public Context(Strategy strategy)
{
_strategy = strategy;
}
public void ContextInterface()
{
_strategy.AlgorithmInterface();
}
}
Участники:
Из диаграммы и кода можно выделить таких участников:
-
Абстрактный класс Strategy (он может быть заменен интерфейсом), который определяет метод
AlgorithmInterface()
. -
Классы ConcreteStrategyA и ConcreteStrategyB, ConcreteStrategyC, которые реализуют Strategy, предоставляя переопределяя метод
AlgorithmInterface()
. Подобных классов-реализаций может быть множество. -
Класс Context хранит ссылку на объект Strategy и связан с абстрактным классом Strategy отношением агрегации.
Неформальная схема паттерна выглядит вот так:
Примеры реализации в .net framework
Паттерн стратегия очень распространенный паттерн в фреймворке:
- LINQ (Language Integrated Query) — это набор методов расширения, принимающих стратегии фильтрации, получения проекции и т. д. Коллекции принимают стратегии сравнения элементов, а значит, любой класс, который принимает IComparer<T> или IEqualityComparer<T>, использует паттерн «Стратегия».
- WCF просто переполнен стратегиями: IErrorHandler — стратегия обработки коммуникационных ошибок; IChannelInitializer — стратегия инициализации канала; IDispatchMessageFormatter — стратегия форматирования сообщений; MessageFilter — стратегия фильтрации сообщений и т. д. Обилие стратегий наблюдается также в Windows Forms, WPF, ASP.NET и других фреймворках.