Pattern Strategy C# | Паттерн Стратегия C#

В этой статье будет рассмотрен паттерн проектирования Стратегия C# — Strategy C#, для чего он нужен и какие проблемы он решает, где можно применять данный шаблон и когда это будет излишним.

Идея паттерна Стратегия (Strategy)

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

Как я уже писал ранее, существует три вида паттернов проектирования:

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

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

Подпишись на группу Вконтакте и Телеграм-канал. Там еще больше полезного контента для программистов.
А на YouTube-канале ты найдешь обучающие видео по программированию. Подписывайся!

Архитектура паттерна проектирования Стратегия

Стратегия
  • Strategy — интерфейс алгоритма
  • Context — клиент стратегии
  • ConcreteStrategyA, ConcreteStrategyB, ConcreteStrategyC — конкретные реализации стратегии

Логика работы паттерна Strategy

Рассмотрим основную логику работы паттерна Стратегия. На самом деле данное поведение настолько часто встречается в повседневном программировании, что мы даже не задумываемся о том, что используем данный паттерн проектирования. Когда мы выделяем интерфейс, мы уже пользуемся стратегией, когда используем наследование тоже. Основная идея заключается в том, что мы определяем интерфейс, а реализуем его отдельно.

Реализация шаблона Стратегия (Strategy) на языке C#

Давайте рассмотрим тривиальный пример реализации данного паттерна. Мы зададим стратегию вывода текста на консоль. А конкретные реализации будут выводить текст разным цветом. Для этого определим интерфейс IConsoleWriter

namespace Strategy
{
    /// <summary>
    /// Интерфейс стратегии.
    /// </summary>
    public interface IConsoleWriter
    {
        /// <summary>
        /// Вывод текста на консоль.
        /// </summary>
        /// <param name="text"> Выводимый текст. </param>
        void WriteText(string text);
    }
}

Теперь создадим три класса, которые будут реализовывать данный интерфейс

using System;

namespace Strategy
{
    /// <summary>
    /// Реализация стратегии вывода текста синим цветом.
    /// </summary>
    public class BlueConsoleWriter : IConsoleWriter
    {
        /// <summary>
        /// Вывод текста на консоль.
        /// </summary>
        /// <param name="text"> Выводимый текст. </param>
        public void WriteText(string text)
        {
            // Проверяем входные данные на корректность.
            if(string.IsNullOrWhiteSpace(text))
            {
                throw new ArgumentNullException(nameof(text));
            }

            // Устанавливаем синий цвет.
            Console.ForegroundColor = ConsoleColor.Blue;

            // Выводим на консоль.
            Console.WriteLine(text);
        }
    }
}
using System;

namespace Strategy
{
    /// <summary>
    /// Реализация стратегии вывода текста зеленым цветом.
    /// </summary>
    public class GreenConsoleWriter : IConsoleWriter
    {
        /// <summary>
        /// Вывод текста на консоль.
        /// </summary>
        /// <param name="text"> Выводимый текст. </param>
        public void WriteText(string text)
        {
            // Проверяем входные данные на корректность.
            if (string.IsNullOrWhiteSpace(text))
            {
                throw new ArgumentNullException(nameof(text));
            }

            // Устанавливаем зеленый цвет.
            Console.ForegroundColor = ConsoleColor.Green;

            // Выводим на консоль.
            Console.WriteLine(text);
        }
    }
}
using System;

namespace Strategy
{
    /// <summary>
    /// Реализация стратегии вывода текста красным цветом.
    /// </summary>
    public class RedConsoleWriter : IConsoleWriter
    {
        /// <summary>
        /// Вывод текста на консоль.
        /// </summary>
        /// <param name="text"> Выводимый текст. </param>
        public void WriteText(string text)
        {
            // Проверяем входные данные на корректность.
            if (string.IsNullOrWhiteSpace(text))
            {
                throw new ArgumentNullException(nameof(text));
            }

            // Устанавливаем красный цвет.
            Console.ForegroundColor = ConsoleColor.Red;

            // Выводим на консоль.
            Console.WriteLine(text);
        }
    }
}

Ну и наконец создадим клиента, который будет работать со стратегией, обращаясь к ее конкретным реализациям.

using System;
using System.Threading;

namespace Strategy
{
    class Program
    {
        static void Main(string[] args)
        {
            // Задаем количество строк, которые будут выведены на экран.
            var count = 25;

            // Задаем задержку между выводом сообщений на консоль.
            var delay = TimeSpan.FromSeconds(1);

            // Создаем коллекцию из конкретных реализаций стратегии.
            // Обратите внимание, что мы используем тип IConsoleWriter,
            // что позволяет разместить в эту коллекцию любой класс,
            // который реализует данный интерфейс стратегии.
            var writers = new IConsoleWriter[]
            {
                new RedConsoleWriter(),
                new BlueConsoleWriter(),
                new GreenConsoleWriter()
            };

            // Простой цикл, чтобы вывести на консоль текст заданное количество раз.
            for(var i = 0; i < count; i++)
            {
                // Получаем индекс элемента из коллекции остатком от деления
                // текущего номера итерации на общее количество элементов в коллекции.
                var index = i % writers.Length;

                // Получаем конкретную реализацию стратегии.
                var writer = writers[index];

                // Подготавливаем случайный текст, который будет выведен на экран.
                var text = Guid.NewGuid().ToString();

                // Выводим текст конкретной реализацией стратегии.
                writer.WriteText(text);

                // Ждем заданный промежуток времени, чтобы выполнялось не слишком быстро.
                Thread.Sleep(delay);
            }

            // Ждем завершения.
            Console.ReadLine();
        }
    }
}

Получаем следующий результат работы приложения

Исходный код приложения можно скачать из репозитория github https://github.com/shwanoff/Strategy

Также рекомендую изучить Паттерн Посредник (Mediator). А еще подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.