15 грудня 2010 р.

"Патерн Вівторка" #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

Немає коментарів:

Дописати коментар