Стратегия (Strategy)

Паттерн Стратегия (Strategy) представляет шаблон проектирования, который определяет набор алгоритмов, инкапсулирует каждый из них и обеспечивает их взаимозаменяемость. В зависимости от ситуации мы можем легко заменить один используемый алгоритм другим. При этом замена алгоритма происходит независимо от объекта, который использует данный алгоритм.

Когда использовать стратегию?

  • Когда есть несколько родственных классов, которые отличаются поведением. Можно задать один основной класс, а разные варианты поведения вынести в отдельные классы и при необходимости их применять
  • Когда необходимо обеспечить выбор из нескольких вариантов алгоритмов, которые можно легко менять в зависимости от условий
  • Когда необходимо менять поведение объектов на стадии выполнения программы
  • Когда класс, применяющий определенную функциональность, ничего не должен знать о ее реализации

Формально паттерн Стратегия можно выразить следующей схемой UML:

Паттерн Стратегия в C#

Формальное определение паттерна на языке C# может выглядеть следующим образом:

public interface IStrategy
{
    void Algorithm();
}
 
public class ConcreteStrategy1 : IStrategy
{
    public void Algorithm()
    {}
}
 
public class ConcreteStrategy2 : IStrategy
{
    public void Algorithm()
    {}
}
 
public class Context
{
    public IStrategy ContextStrategy { get; set; }
 
    public Context(IStrategy _strategy)
    {
        ContextStrategy = _strategy;
    }
 
    public void ExecuteAlgorithm()
    {
        ContextStrategy.Algorithm();
    }
}

Участники

Как видно из диаграммы, здесь есть следующие участники:

  • Интерфейс IStrategy, который определяет метод Algorithm(). Это общий интерфейс для всех реализующих его алгоритмов. Вместо интерфейса здесь также можно было бы использовать абстрактный класс.
  • Классы ConcreteStrategy1 и ConcreteStrategy, которые реализуют интерфейс IStrategy, предоставляя свою версию метода Algorithm(). Подобных классов-реализаций может быть множество.
  • Класс Context хранит ссылку на объект IStrategy и связан с интерфейсом IStrategy отношением агрегации.

В данном случае объект IStrategy заключена в свойстве ContextStrategy, хотя также для нее можно было бы определить приватную переменную, а для динамической установки использовать специальный метод.

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

class Program
{
    static void Main(string[] args)
    {
        Car auto = new Car(4, "Volvo", new PetrolMove());
        auto.Move();
        auto.Movable = new ElectricMove();
        auto.Move();
 
        Console.ReadLine();
    }
}
interface IMovable
{
    void Move();
}
 
class PetrolMove : IMovable
{
    public void Move()
    {
        Console.WriteLine("Перемещение на бензине");
    }
}
 
class ElectricMove : IMovable
{
    public void Move()
    {
        Console.WriteLine("Перемещение на электричестве");
    }
}
class Car
{
    protected int passengers; // кол-во пассажиров
    protected string model; // модель автомобиля
 
    public Car(int num, string model, IMovable mov)
    {
        this.passengers = num;
        this.model = model;
        Movable = mov;
    }
    public IMovable Movable { private get; set; }
    public void Move()
    {
        Movable.Move();
    }
}

В данном случае в качестве IStrategy выступает интерфейс IMovable, определяющий метод Move(). А реализующий этот интерфейс семейство алгоритмов представлено классами ElectricMove и PetroleMove. И данные алгоритмы использует класс Car.

Пример применения: переключаться между различными эвристиками для поиска A *, в зависимости от того, в какой местности вы находитесь, или, возможно, даже использовать одну и ту же среду A * для выполнения поиска пути и более общего планирования

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *