components

Decorator – Design Patterns #2

Każdy lubi jeść a wszyscy co tutaj wchodzą lub znaczna większość jest zwolennikiem kawy. Sam bardzo lubię zarówno jeść jak i pić kawę… Załóżmy więc sytuację: wchodzimy do kawiarni i zamawiamy dużą kawę z bitą śmietaną i czekoladą (mniam!) lub do pizzerii – a jak to na wybrednego człowieka jakim jest programista przystało zamawiamy pizzę tylko z wybranymi składnikami i modyfikujemy istniejące wybory na te które bardziej nam pasują. Pizza? Super, aż zrobiłem się głodny, ale co to ma wspólnego ze wzorcami projektowymi? O dziwo ma dość sporo, ponieważ w systemie zarządzania kawiarnią lub pizzerią jest kilka sposobów na rozwiązanie tego problemu. Załóżmy jednak, że chodzi o kawę. Aby rozwiązać problem zamówień możemy stworzyć bardzo dużą ilość klas jak np. CoffeWithChocolateAndWhippedCream, CoffeWithChocolate, CoffeWithDoubleChocolate itd… Tak aby każda klasa odpowiadała nam danemu zamówieniu, jest to jednak mało praktyczne podejście! Co gdybyśmy mieli różne rodzaje kawy a dodatków byłoby dużo więcej? Stworzylibyśmy naprawdę dużo klas, w których łatwo byłoby się pogubić. A gdzie czystość kodu? Z jednej zasad SOLID wynika, że kod powinien być otwarty na rozszerzenia i zamknięty na modyfikację (Open-closed principal).  Z pomocą przychodzi nam wzorzec Dekorator. Sam w sobie jest co prawda mniej używany, więcej w kombinacji np. z wzorcem Builder lub Factory ale o tych wzorcach i ich połączeniu napiszę niebawem. Zacznijmy może od książkowej definicji naszego Dekoratora, jak piszą w Rusz Głową! Wzorce Projektowe:

Dekorator – pozwala na dynamiczne przydzielenie danemu obiektowi nowych zachowań. Dekoratory dają elastyczność, podobną do tej jaką daje dziedziczenie, oferując jednak w zamian znacznie rozszerzoną funkcjonalność

Definicja ta jest dość prosta tak samo jak przedstawienie tego wzorca na diagramie

diagram

Nie jest on specjalnie skomplikowany ale jak pisałem wyżej pomaga on nam zachować przede wszystkim zasadę Open/Close. Wzorzec sam w sobie nie jest jednak doskonały, tworzymy trochę zduplikowanego kodu. Przejdźmy jednak co implementacji wzorca. Całość wykonamy na przykładzie systemu obsługi zamówień dla kawiarni – zostaniemy przy kawie, ponieważ opisując taki sam system dla pizzy jeszcze zachęcę kogoś do zamówienia jej a warto pamiętać o zdrowym jedzeniu. Przejdźmy jednak do działania:

Tworzymy pierw bazową klasę abstrakcyjną Kawy posiadającą podstawowe metody, które będziemy nadpisywać we wszystkich klasach dziedziczących.

Coffee

Następnie tworzymy sobie bazowe typy kawy, którą serwuje nasza kawiarnia. Wiadomo przecież, że kawiarnia nie będzie podawała tylko jednego rodzaju kawy. Tak więc dziedziczymy po naszej podstawowej klasie Kawy nadpisując jej właściwości odpowiednimi dla danych klas:

ConcreteCoffee1

ConcreteCoffee2

ConcreteCoffee3

Póki co w systemie dla naszej kawiarni jesteśmy w stanie zaproponować gościom tylko podstawowe rodzaje kawy bez żadnych dodatków. Jednak obecny świat pozwala na dowolną zmianę nawet samochodów na stronie producentów, tak więc z kawą nie może być inaczej! Aby tego dokonać musimy zaimplementować nasz „dekorator” do kawy, czyli dodawanie do niej dodatków. Tworzymy więc znów klasę abstrakcyjną, po której każdy z naszych poszczególnych dodatków będzie dziedziczył i nadpisywał jej metody.

CoffeeDecorator

Nie było to chyba aż tak trudne? Teraz mając już nasz bazowy dekorator możemy brać się za wymyślanie dodatków. Proponuję 3 podstawowe, ponieważ kawiarnia dopiero rusza, niech będzie to czekolada, bita śmietana i mleko.

ConcreteDecorator1ConcreteDecorator2ConcreteDecorator3

Mamy już stworzony całkiem przyjazny system zamawiania kawy, wystarczy teraz tylko stworzyć instancję z jednej klasy bazowej (ConcreteComponent) a następnie udekorować ją zgodnie z wymaganiami klienta. Poniżej przedstawiony kod wraz z wynikiem i strukturą solucji.

mainsolutionresult

 

I tyle. Nic wielkiego, nic ciężkiego. Właśnie nasz arsenał ze znajomością wzorców został wzbogacony o Dekoratora. Niestety ze wzorcami projektowymi jest tak, że jak je znasz to jesteś ich w stanie użyć ale już jak nie masz o nich pojęcia to nie wygoooglujesz sobie tego. Jest to na pewno etap przez który każdy rozwijający się programista przechodzi. Postaram się aby wpisy o wzorcach pojawiały się co 2 tygodnie. Myślę, że jest to optymalny dla mnie czas na opracowanie materiału. Zachęcam do komentowania, lajkowania itd. itp. Tymczasem do usłyszenia za 2 tygodnie z wzorcem Factory. Na koniec standardowo piosenka:

PS. Postanowiłem, że posty będą wychodzić co 2 piątek o godzinie 09:09, tak więc zapraszam na bloga w piątek 03.11 o godzinie 09:09 🙂

 

Jedna myśl w temacie “Decorator – Design Patterns #2

  1. Pingback: dotnetomaniak.pl

Możliwość komentowania jest wyłączona.