sobota, 10 października 2009

Strategy Pattern

Wzorce projektowe w swoim zamyśle mają ułatwić pracę developerów na etapie projektowania jak i późniejszego pielęgnowania kodu. Dobrze zaprojektowana aplikacja, pozwala na łatwe rozszerzanie poprzez dodawanie nowej funkcjonalności czy też zmiany już istniejącej.

Jednym z ważniejszych wzorców projektowych jest niewątpliwie strategia. Jest to jeden z behawioralnych wzorców projektowych, czyli opisujący algorytmy i komunikację pomiędzy obiektami.
Strategy Pattern definiuje rodzinę powiązanych ze sobą algorytmów, które mogą być wymieniane ze sobą w zależności od wymagań klienta.
Diagram ogólny UML mógłby mieć następującą postać:

Jak widać klasa Klient zawiera w sobie referencję do interfejsu Strategy. Dzięki metodzie changeStrategy możemy zmienić zachowanie naszego obiektu.
Prosty przykład:
Wyobraźmy sobie, że mamy klasę KinoDomowe. Klasa ta może zawierać różne pola. Jednym z ważniejszych składników tworzących kino domowe jest dźwięk. Dźwięk może być kodowany w różnych formatach. Spójrzmy na diagram klas:

 Dzięki wykorzystaniu wzorca Strategy jesteśmy w stanie w łatwy sposób zmieniać sposób kodowania dźwięku. Dlaczego taki sposób jest lepszy od np. dodania odpowiednich pól do klasy Kino Domowe i ustawianie ich wartości w zależności od tego jaki dźwięk jest aktualnie używany? Jeśli stworzylibyśmy większą hierarchię klas która mogłaby wyglądać np. tak:

W takim przypadku użycie naszego wzorca daje dużo większe pole do popisu. Jeśli korzystalibyśmy ze zwykłego dziedziczenia i polimorfizmu nie uzyskalibyśmy wystarczająco zadowalających efektów, które w łatwy sposób w przyszłości można by było modyfikować.
A teraz krótki kod do przykładu:


public abstract class KinoDomowe
    {
        private int przekatnaEkranu;
        private int mocNaglosnienia;
        private IKodowanieDzwieku kodowanieDzwieku;

        public KinoDomowe(int przekatnaEkranu, 
               int mocNaglosnienia)
        {
            this.mocNaglosnienia = mocNaglosnienia;
            this.przekatnaEkranu = przekatnaEkranu;
        }

        public IKodowanieDzwieku KodowanieDzwieku
        {
            get
            {
                return kodowanieDzwieku;
            }
            set
            {
                kodowanieDzwieku = value;
            }
        }

        public override string ToString()
        {
            return string.Format(@"Kino domowe z ekranem 
            o przekatnej {0}, mocy naglosnienia {1} oraz 
            grajace w systemie {2}", przekatnaEkranu,
            mocNaglosnienia, kodowanieDzwieku.KodujDzwiek());
        }
    }

    public interface IKodowanieDzwieku
    {
        string KodujDzwiek();
    }

    public class LPCM : IKodowanieDzwieku
    {
        #region IKodowanieDzwieku Members

        public string KodujDzwiek()
        {
            return string.Format("LPCM");
        }

        #endregion
    }

    public class DolbyProLogic : IKodowanieDzwieku
    {
        #region IKodowanieDzwieku Members

        public string KodujDzwiek()
        {
            return string.Format("DolbyProLogic");
        }

        #endregion
    }

    public class DolbyDigital : IKodowanieDzwieku
    {
        #region IKodowanieDzwieku Members

        public string KodujDzwiek()
        {
            return string.Format("DolbyDigital");
        }

        #endregion
    }


        static void Main(string[] args)
        {
            KinoDomowe kinoDomowe = new KinoDomowe(40, 200);
            kinoDomowe.KodowanieDzwieku = new LPCM();
            Console.WriteLine(kinoDomowe.ToString());
            Console.WriteLine("----------------------");
            kinoDomowe.KodowanieDzwieku = new DolbyDigital();
            Console.WriteLine(kinoDomowe.ToString());
        }

Podsumowując: Wzorce projektowe przydają się i należy się ich uczyć. W wielu sytuacjach mogą nam oszczędzić czas i nerwy.

Brak komentarzy:

Prześlij komentarz