Назад Зміст

Програмна реалізація

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

Постановка задачі:

Створити модель ставка, в якому плавають і крякають качки різних видів.

Виділяємо змінні компоненти та інкапсулюємо їх, щоб у майбутньому можна було змінювати або розширювати без впливу на сталу частину.

Шаблон "Стратегія" - Демонстрація з качками

Ця демонстрація показує, як шаблон "Стратегія" дозволяє динамічно змінювати поведінку об'єктів.

Обрати тип качки:

Змінити поведінку:

Поведінка польоту:
Поведінка крякання:
Оберіть тип качки та натисніть "Продемонструвати поведінку"

Відділяємо змінні компоненти

Щоб відокремити «змінне від сталого», ми створюємо два набори класів (зовсім незалежних від Duck): один — для fly, інший — для quack. Кожен набір містить реалізацію відповідної поведінки.

Ми знаємо, що fly() і quack() — це частини класу Duck, які змінюються в залежності від підкласу.

Щоб відділити ці аспекти поведінки від класу Duck, ми винесли обидва методи з класу Duck та створили новий набір класів для представлення кожного з аспектів.

Створюємо інтерфейс типу польоту — IFlyBehavior

public interface IFlyBehavior
{
    void Fly();  // Метод для виконання польоту
    bool CanFly { get; }  // Властивість, що вказує на можливість польоту
}

Створюємо інтерфейс типу звуку — IQuackBehavior

public interface IQuackBehavior
{
    /// 
    /// Генерує звук крякання
    /// 
    /// Рядок, що представляє звук крякання
    string Quack();  // Більш стандартна назва методу
}

Створюємо класи, які моделюють різні види польоту:

Створюємо класи, які моделюють різні звуки:

Отже, цього разу інтерфейси реалізуються не в класах Duck. Замість цього ми створюємо набір класів, єдиним сенсом яких є представлення певної поведінки.

Інтеграція поведінки з класом Duck

І тепер інтерфейс поведінки реалізує клас поведінки, а не клас Duck.

Підкласи Duck використовують поведінку, представлену через інтерфейс (IFlyBehavior або IQuackBehavior), тому фактична реалізація цієї поведінки (конкретні класи, що реалізують ці інтерфейси) не прив’язана до конкретного підкласу Duck.

Ось як це реалізується:

  1. У класі Duck додаються дві змінні екземпляру: IFlyBehavior та IQuackBehavior, оголошені як типи інтерфейсів, а не конкретні класи. На етапі виконання кожен об’єкт присвоює цим змінним поліморфні реалізації поведінки (наприклад, FlyWithWings, Squeak тощо).
  2.  // Абстрактний клас Duck зі стратегіями поведінки
    public abstract class Duck
    {
        // Поля для зберігання стратегій поведінки
        protected IFlyBehavior flyBehavior;
        protected IQuackBehavior quackBehavior;
    
        // Властивості для доступу та зміни стратегій
        public IQuackBehavior QuackBehavior 
        { 
            get => quackBehavior; 
            set => quackBehavior = value; 
        }
    
        public IFlyBehavior FlyBehavior 
        { 
            get => flyBehavior; 
            set => flyBehavior = value; 
        }
    
        // Абстрактний метод для відображення зовнішнього вигляду качки
        public abstract object Display();
    
        // Методи для виконання поведінки
        public object PerformFly() => flyBehavior.Fly();
    
        public object PerformQuack() => quackBehavior.Quacking();
    
        // Загальна поведінка для всіх качок
        public string Swim => "Всі качки вміють плавати, навіть іграшкові! 🦆🏊";
    }
  3. Методи fly() та quack() видаляються з класу Duck (і всіх підкласів), тому що ця поведінка переноситься до класів реалізації інтерфейсів. У класі Duck замість них з’являються методи performFly() та performQuack().
  1. MallardDuck — реальна качка.
  2.   // Клас справжньої качки-крякви
    public class MallardDuck : Duck
    {
        public MallardDuck()
        {
            // Встановлюємо природне крякання
            quackBehavior = new Quack();
            
            // Встановлюємо політ з маханням крил
            flyBehavior = new FlyWithWings();
        }
    
        // Відображення зовнішнього вигляду качки
        public override object Display => "Я справжня качка-кряква! 🦆🌿";
    }
  3. ModelDuck — модель качки.
  4.   // Клас модельної качки (дерев'яної іграшки)
    public class ModelDuck : Duck
    {
        public ModelDuck()
        {
            // Встановлюємо реактивний політ (нестандартна поведінка для іграшки)
            flyBehavior = new FlyRocketPowered();
            
            // Встановлюємо відсутність звуку (мовчазна іграшка)
            quackBehavior = new MuteQuack();
        }
    
        // Відображення модельної качки
        public override object Display => "Я модельна качка-іграшка 🦆";
    }
  5. RubberDuck — гумова качка.

Зрештою, створюємо ставок із різними качками і викликаємо їхні методи для демонстрації різної поведінки.

 using System;

class Program
{
    static void Main(string[] args)
    {
        // Створюємо ставок з різними типами качок
        Duck[] ducks = { new MallardDuck(), new ModelDuck(), new RubberDuck() };
        
        // Демонструємо поведінку кожної качки
        foreach (Duck duck in ducks)
        {
            Console.WriteLine("=== Демонстрація качки ===");
            Console.WriteLine("Зовнішній вигляд: " + duck.Display);
            Console.WriteLine("Плавання: " + duck.Swim);
            Console.WriteLine("Звук: " + duck.PerformQuack());
            Console.WriteLine("Політ: " + duck.PerformFly());
            Console.WriteLine();
        }
        
        Console.ReadKey();
    }
}

/*
Приклад виводу:

=== Демонстрація качки ===
Зовнішній вигляд: Я справжня качка-кряква! 🦆🌿
Плавання: Всі качки вміють плавати, навіть іграшкові! 🦆🏊
Звук: Кря-кря! 🦆
Політ: Я літаю, махаючи крилами! 🦆✈️

=== Демонстрація качки ===
Зовнішній вигляд: Я модельна качка-іграшка 🦆
Плавання: Всі качки вміють плавати, навіть іграшкові! 🦆🏊
Звук: (ніякого звуку) 🦆
Політ: Я лечу на реактивній тязі! 🚀

=== Демонстрація качки ===
Зовнішній вигляд: Я гумова качка-іграшка 🦆🎈
Плавання: Всі качки вміють плавати, навіть іграшкові! 🦆🏊
Звук: Піп-піп! 🦆🔊
Політ: Я не літаю. 🦆
*/

Програмна реалізація стратегії (Strategy)


using System;

// Інтерфейси поведінки
public interface IFlyBehavior
{
    object Fly();
}

public interface IQuackBehavior
{
    string Quacking();
}

// Реалізації поведінки польоту
public class FlyWithWings : IFlyBehavior
{
    public object Fly() => "Я літаю, махаючи крилами! 🦆✈️";
}

public class FlyNoWay : IFlyBehavior
{
    public object Fly() => "Я не літаю. 🦆";
}

public class FlyRocketPowered : IFlyBehavior
{
    public object Fly() => "Я лечу на реактивній тязі! 🚀";
}

// Реалізації поведінки крякання
public class Quack : IQuackBehavior
{
    public string Quacking() => "Кря-кря! 🦆";
}

public class MuteQuack : IQuackBehavior
{
    public string Quacking() => "(ніякого звуку) 🦆";
}

public class Squeak : IQuackBehavior
{
    public string Quacking() => "Піп-піп! 🦆🔊";
}

// Базовий клас качки
public abstract class Duck
{
    protected IFlyBehavior flyBehavior;
    protected IQuackBehavior quackBehavior;

    public IQuackBehavior QuackBehavior 
    { 
        get => quackBehavior; 
        set => quackBehavior = value; 
    }

    public IFlyBehavior FlyBehavior 
    { 
        get => flyBehavior; 
        set => flyBehavior = value; 
    }

    public abstract object Display { get; }

    public object PerformFly() => flyBehavior.Fly();

    public string PerformQuack() => quackBehavior.Quacking();

    public string Swim => "Всі качки вміють плавати, навіть іграшкові! 🦆🏊";
}

// Конкретні типи качок
public class MallardDuck : Duck
{
    public MallardDuck()
    {
        quackBehavior = new Quack();
        flyBehavior = new FlyWithWings();
    }

    public override object Display => "Я справжня качка-кряква! 🦆🌿";
}

public class ModelDuck : Duck
{
    public ModelDuck()
    {
        flyBehavior = new FlyRocketPowered();
        quackBehavior = new MuteQuack();
    }

    public override object Display => "Я модельна качка-іграшка 🦆";
}

public class RubberDuck : Duck
{
    public RubberDuck()
    {
        flyBehavior = new FlyNoWay();
        quackBehavior = new Squeak();
    }

    public override object Display => "Я гумова качка-іграшка 🦆🎈";
}

// Головна програма
class Program
{
    static void Main(string[] args)
    {
        Console.OutputEncoding = System.Text.Encoding.UTF8;
        
        // Створюємо ставок з різними типами качок
        Duck[] ducks = { new MallardDuck(), new ModelDuck(), new RubberDuck() };
        
        // Демонструємо поведінку кожної качки
        foreach (Duck duck in ducks)
        {
            Console.WriteLine("=== Демонстрація качки ===");
            Console.WriteLine("Зовнішній вигляд: " + duck.Display);
            Console.WriteLine("Плавання: " + duck.Swim);
            Console.WriteLine("Звук: " + duck.PerformQuack());
            Console.WriteLine("Політ: " + duck.PerformFly());
            Console.WriteLine();
        }

        // Демонстрація зміни поведінки на льоту
        Console.WriteLine("\n=== Експеримент: Модельна качка тепер літає з крилами ===");
        Duck model = new ModelDuck();
        Console.WriteLine("Початковий політ: " + model.PerformFly());
        model.FlyBehavior = new FlyWithWings();
        Console.WriteLine("Новий політ: " + model.PerformFly());
        
        Console.ReadKey();
    }
}

Назад Зміст