środa, 12 maja 2010

Facade Pattern

Wzorzec ten umożliwia na dostęp do skomplikowanego systemu, poprzez uproszczony interfejs. Oczywiście system nadal jest dostępny bezpośrednio. Dla każdego systemu może istnieć wiele interfejsów pomocniczych. Mogą one dodatkowo rozszerzać funkcjonalność oryginalnego systemu.

Facade Pattern często jest mylony z Adapterem. Należy sobie jednak zdać sprawę że Adapter zamienia interfejs na taki który oczekuje klient a Facade upraszcza działanie na interfejsie.
Zobaczmy na przykładowy system:


Tak więc mamy tu z systemem zarządzającym prywatnym domem. Przeanalizujmy (będąc na miejscu właściciela takiego domu) co należy zrobić aby np. oglądnąć film na DVD. A więc kolejno należy: włączyć światło, włączyć telewizor, włączyć amplifer (ustawić jego głośność oraz wybrać system dźwięku), włączyć odtwarzanie filmu na odtwarzaczu DVD. Jak widać prosta czynność a może zająć bardzo dużo czasu.
Zobaczmy jak to wygląda z poziomu kodu:

Najpierw kod systemu:

    public class Amplifier
    {
        public void On()
        {
            Console.WriteLine("Amplifier set On");
        }

        public void Off()
        {
            Console.WriteLine("Amplifier set Off");
        }

        public void DolbyDigital()
        {
            Console.WriteLine("Amplifier set DolbyDigital system");
        }

        public void ProLogic()
        {
            Console.WriteLine("Amplifier set ProLogic system");
        }
    }

    public class Dvd
    {
        private Amplifier _amplifier;

        public Amplifier Amplifier
        {
            get
            {
                return _amplifier;
            }
            set
            {
                _amplifier = value;
            }
        }

        public void On()
        {
            Console.WriteLine("DVD power On");
        }

        public void Off()
        {
            Console.WriteLine("DVD power Off");
        }

        public void Play()
        {
            Console.WriteLine("Start Plaing DVD film");
        }

        public void ChangeDvd()
        {
            Console.WriteLine("Changing DVD film");
        }
    }

    public class House
    {
        private Kitchen _kitchen;
        private LivingRoom _livingRoom;

        public Kitchen Kitchen
        {
            get
            {
                return _kitchen;
            }
            set
            {
                _kitchen = value;
            }
        }

        public LivingRoom LivingRoom
        {
            get
            {
                return _livingRoom;
            }
            set
            {
                _livingRoom = value;
            }
        }
    }

    public class Kitchen
    {
        private Refrigerator _refrigerator;
        private Microwave _microwave;
        private Toaster _toaster;
        private Light _light;

        public Refrigerator Refrigerator
        {
            get
            {
                return _refrigerator;
            }
            set
            {
                _refrigerator = value;
            }
        }

        public Microwave Microwave
        {
            get
            {
                return _microwave;
            }
            set
            {
                _microwave = value;
            }
        }

        public Toaster Toaster
        {
            get
            {
                return _toaster;
            }
            set
            {
                _toaster = value;
            }
        }

        public Light Light
        {
            get
            {
                return _light;
            }
            set
            {
                _light = value;
            }
        }
    }

    public class Light
    {
        public void On()
        {
            Console.WriteLine("Light On");
        }

        public void Off()
        {
            Console.WriteLine("Light Off");
        }
    }

    public class LivingRoom
    {
        private Light _light;
        private Tv _tv;
        private Dvd _dvd;

        public Light Light
        {
            get
            {
                return _light;
            }
            set
            {
                _light = value;
            }
        }

        public Tv Tv
        {
            get
            {
                return _tv;
            }
            set
            {
                _tv = value;
            }
        }

        public Dvd Dvd
        {
            get
            {
                return _dvd;
            }
            set
            {
                _dvd = value;
            }
        }
    }

    public class Microwave
    {
        private int _time;
        private int _temperature;

        public int Time
        {
            get
            {
                return _time;
            }
            set
            {
                if (value > 0 && value <= 30)
                {
                    _time = value;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("The value is not from range 1 and 30");
                }
            }
        }

        public int Temperature
        {
            get
            {

                return _temperature;
            }
            set
            {
                if (value > 49 && value < 301)
                {
                    _temperature = value;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("The value is not from range 50 and 300");
                }
            }
        }

        public void On()
        {
            Console.WriteLine("Microwave power On");
        }

        public void Off()
        {
            Console.WriteLine("Microwave power Off");
        }
    }

    public class Refrigerator
    {
        private int _temperature;

        public int Temperature
        {
            get
            {
                return _temperature;
            }
            set
            {
                if (value > -21 && value < 5)
                {
                    _temperature = value;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("The value is not from range -20 and 5");
                }
            }
        }

        public void On()
        {
            Console.WriteLine("The Refrigerator power On");
        }

        public void Off()
        {
            Console.WriteLine("The Refrigerator power Off");
        }
    }

    public class Toaster
    {
        private int _time;

        public int Time
        {
            get
            {
                return _time;
            }
            set
            {
                if (value > 0 && value < 11)
                {
                    _time = value;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("The value is not from range 1 and 10");
                }
            }
        }

        public void On()
        {
            Console.WriteLine("The Toaster power On");
        }

        public void Off()
        {
            Console.WriteLine("The Toaster power On");
        }
    }

    public class Tv
    {
        private int _volume;
        private int _canal;
        private Amplifier _amplifier;

        public int Volume
        {
            get
            {
                return _volume;
            }
            set
            {
                if (value > -1 && value < 51)
                {
                    _volume = value;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("The value is not from range 0 and 50");
                }
            }
        }

        public int Canal
        {
            get
            {
                return _canal;
            }
            set
            {
                if (value > 0 && value < 300)
                {
                    _canal = value;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("The value is not from range 1 and 299");
                }
            }
        }

        public Amplifier Amplifier
        {
            get
            {
                return _amplifier;
            }
            set
            {
                _amplifier = value;
            }
        }

        public void On()
        {
            Console.WriteLine("The TV power On");
        }

        public void Off()
        {
            Console.WriteLine("The Refrigerator power Off");
        }
    }

Teraz przejdźmy do sedna, czyli uruchomienia odtwarzania filmu na płycie DVD:

        static void Main(string[] args)
        {
            House house = new House();
            LivingRoom livingRoom = new LivingRoom();
            livingRoom.Dvd = new Dvd();
            livingRoom.Light = new Light();
            livingRoom.Tv = new Tv();
            livingRoom.Tv.Amplifier = new Amplifier();
            house.LivingRoom = livingRoom;

            //Odtwarzanie jednego filmu...
            house.LivingRoom.Light.On();
            house.LivingRoom.Tv.On();
            house.LivingRoom.Tv.Amplifier.On();
            house.LivingRoom.Tv.Volume = 10;
            house.LivingRoom.Tv.Amplifier.ProLogic();
            house.LivingRoom.Dvd.Play();
        }

Wykonanie tego wszystkiego, aby obejrzeć jeden film? A co w przypadku gdy odchodzimy od telewizora? Trzaba by znów wszystko powtórzyć tyko w odwrotnej kolejności (Off zamiast On).

Sporo pracy prawda? Właśnie w takich chwilach przydaje się Facade. Stworzymy sobie klasę InteligentLivingRoom która umożliwi nam w prosty sposób na odtwarzanie filmów:

    public class InteligentLivingRoom
    {
        public LivingRoom LivingRoom { get; set; }

        public InteligentLivingRoom(LivingRoom lr)
        {
            this.LivingRoom = lr;
        }

        public void PlayDVDFilm()
        {
            LivingRoom.Light.On();
            LivingRoom.Tv.On();
            LivingRoom.Tv.Amplifier.On();
            LivingRoom.Tv.Volume = 10;
            LivingRoom.Tv.Amplifier.ProLogic();
            LivingRoom.Dvd.Play();
        }
    }

I kod który pozwoli nam na obejrzenie filmu:

        static void Main(string[] args)
        {
            House house = new House();
            LivingRoom livingRoom = new LivingRoom();
            livingRoom.Dvd = new Dvd();
            livingRoom.Light = new Light();
            livingRoom.Tv = new Tv();
            livingRoom.Tv.Amplifier = new Amplifier();
            house.LivingRoom = livingRoom;

            /*
             * Ten fragment kodu zastępujemy tym co poniżej się znajduje
            house.LivingRoom.Light.On();
            house.LivingRoom.Tv.On();
            house.LivingRoom.Tv.Amplifier.On();
            house.LivingRoom.Tv.Volume = 10;
            house.LivingRoom.Tv.Amplifier.ProLogic();
            house.LivingRoom.Dvd.Play();
             */

            InteligentLivingRoom inteligentLivingRoom = new InteligentLivingRoom(livingRoom);
            inteligentLivingRoom.PlayDVDFilm();
            //czy nie wygląda to lepiej?
        }

Jak widać kilka linijek kodu, zamieniliśmy niespełna dwoma. W naszej klasie InteligentLivingRoom możemy dodać kolejne metody, jak i również możemy stworzyć nowe klasy "ułatwiacze". Wszystko to pomoże łatwiej i przyjemniej korzystać z rozbudowanych systemów zawierających dużą ilość klas.

Ogólny schemat UML tego wzorca przedstawia się następująco:
Zrozumienie go po przeanalizowaniu przykładu nie powinno sprawić problemu.

Brak komentarzy:

Prześlij komentarz