“Патерн Вівторка” #19: Стратегія (Strategy)

Просто як двері – якщо на дворі дощ, то ви берете парасольку і куртку, а якщо палить сонце – то ви берете футболку і сонцезахисні окуляри. Що одівати є вашою стратегією, яку ви міняєте в залежності від обставин. Але замість того, щоб дивитися за вікно яка погода а потім мандрувати до шафки із одягом і вибирати що надягнути а далі, пам’ятаючи яка погода, йти до іншої шафки і брати парасольку або окуляри, ви просто піднімаєтеся із ліжка протираєте очі і вам у руки жінка(чоловік, що маловірогідно) подає потрібний одяг і аксесуари. Іншими словами стратегія на сьогоднішній день просто була подана і ви нею скористалися.

СТРАТЕГІЯ

Стратегія – це дизайн патерн, що зберігає сім’ю алгоритмів і дозволяє їх міняти незалежно та переключатися між ними.

Припустимо що в класі Я (Myself) ми маємо метод піти на вулицю GoOutside() в якому ми вибираємо собі одяг і шуруємо на вулицю.

Метод міг виглядати подібно до ось цього:

public void GoOutside()
{
var weather = Weather.GetWeather();
string clothes = GetClothes(weather);
string accessories = GetAccessories(weather);
Console.WriteLine("Today I wore {0} and took {1}", clothes, accessories);
}

private string GetAccessories(string weather)
{
string accessories;
switch (weather)
{
case "sun":
accessories = "sunglasses";
break;
case "rain":
accessories = "umbrella";
break;
default:
accessories = "nothing";
break;
}
return accessories;
}

private string GetClothes(string weather)
{
string clothes;
switch (weather)
{
case "sun":
clothes = "T-Shirt";
break;
case "rain":
clothes = "Coat";
break;
default:
clothes = "Shirt";
break;
}
return clothes;
}

воно звичайно добре, але як тільки вам треба буде прилаштовуватися до випавшого снігу, вам прийдеться добавити ще один case в троьхсот місцях. Із одної сторони воно не складно, але із іншої вас може “дістати” або код із методом GoOutside() вже не можна буде міняти. Що тоді?

Тут я наводжу приклад із switch, тому що Strategy – це елегантний спосіб позбутися цього чуда.

internal class Myself
{
private IWearingStrategy _wearingStrategy = new DefaultWearingStrategy();

public void ChangeStrategy(IWearingStrategy wearingStrategy)
{
_wearingStrategy = wearingStrategy;
}

public void GoOutside()
{
var clothes = _wearingStrategy.GetClothes();
var accessories = _wearingStrategy.GetAccessories();

Console.WriteLine("Today I wore {0} and took {1}", clothes, accessories);
}
}

Як бачимо ми маємо інтерфейс стратегії із двома методами. Нумо глянемо як виглядає стратегія на сонячний день:

public interface IWearingStrategy
{
string GetClothes();
string GetAccessories();
}

class SunshineWearingStrategy : IWearingStrategy
{
public string GetClothes()
{
return "T-Shirt";
}

public string GetAccessories()
{
return "sunglasses";
}
}

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

var me = new Myself();
me.ChangeStrategy(new RainWearingStrategy());
me.GoOutside();

Вивід простий: “Today I wore Coat and took umbrella”

Ще одним (але не моїм) гарним прикладом є зміна стратегії сортування списку в залежності від його розміру. Всі ми знаємо що для малої кількості даних достатньо сортування вставками або якийсь інший простий спосіб, для відносно великих списків найоптимальніше використовувати швидке сортування, а для дуже великої к-ті даних пірамідальне. Так от, алгоритм зберігається у своєму класі і в залежності від кількості елементів ми просто міняємо реалізацію алгоритму.

Моя табличка Патернів

Developer's RoadMap To Success

Add a Comment

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *