Przejdź do treści
Strona główna » Blog » Wzorzec Dekorator

Wzorzec Dekorator

Kolejnym wzorcem projektowym, który opiszę będzie tytułowy dekorator. Wzorzec ten łatwo można sobie wyobrazić jako implementację pracy dekoratora wnętrz, który dostając mieszkanie nieurządzone zajmuje się przyozdabianiem go w różne gadżety. W efekcie dostajemy to samo mieszkanie jednak jest ono już zmodyfikowane. Jak to wygląda w programowaniu? Zapraszam do lektury.

Przedstawmy problem

Wzorzec dekorator zakłada istnienie dwóch rodzajów klas, które nazwiemy potocznie klasą dekorowana i dekorująca. Na przywołanym przykładzie dekoratora wnętrz klasą dekorowaną będzie mieszkanie, a klasą dekorującą ozdoba, bądź element dekoratorski, który przystraja to mieszkanie. Każda czynność wykonana przez dekoratora w mieszkaniu powoduje, że mieszkanie pozostaje ciągle mieszkaniem lecz zyskuje nowe funkcjonalności.

W tym momencie można by wprost pomyśleć o tym, że w takim razie dziedziczenie idealnie nadaje się do tego aby taki mechanizm odwzorować. Problem polega na tym, że każdy dekorator ma całą paletę utartych ścieżek i elementów które stosuje w swojej pracy. W końcu po co przy każdym projekcie wymyślać koło od nowa. Tworzenie finalnego projektu za każdym razem wymagałoby napisania przez dekoratora wielu klas, z których każda kolejna dodawałaby jeden efekt w mieszkaniu co przy wielu projektach przez niego wykonywanych namnożyłoby mnóstwo klas, które ciężko byłoby ponownie wykorzystać. Zobaczmy przykład poniżej:

mieszkanie 1

class Mieszkanie {
    int iloscScian = 4;
}

class MieszkanieJasne
extends Mieszkanie{
    String kolor = "biały";
}

class MieszkanieBialeDuze
extends MieszkanieBiale{
    double powierzchniaM2 = 120;
}

class MieszkanieBialeDuzeZBalkonem
extends MieszkanieBialeDuze{
    boolean balkon = true;
}

mieszkanie 2

class Mieszkanie {
    int iloscScian = 4;
}

class MieszkanieCiemne 
extends Mieszkanie{
    String kolor = "czarny";
}

class MieszkanieCiemneMale
extends MieszkanieCiemne{
    double powierzchniaM2 = 42;
}

class MieszkanieCiemneMaleZTarasem
extends MieszkanieCiemneMale{
    boolean taras = true;
}

Zauważmy że gdybyśmy chcieli tylko utworzyć mieszkanie jasne małe z tarasem to możemy wykorzystać tylko klasę MieszkanieJasne, natomiast pozostałe 2 należałoby dopisać. To nie jest wygodne rozwiązanie. Dodatkowo pojawia się problem w momencie gdy chcemy porównać ze sobą dwa obiekty. Zauważmy że tak naprawdę obydwa są różnego typu więc wprost nie można ich do siebie przyrównać.

Rozwiążmy problem

Idealnym rozwiązaniem dla dekoratora wnętrz byłoby gdyby mógł każde mieszkanie komponować z gotowych utworzonych wcześniej komponentów, a następnie dla własnego rozeznania ocenić atrakcyjność rozwiązania w oparciu o jakiś parametr. W tym momencie triumfalnie wkracza wzorzec dekorator.

Na samym początku popatrzmy na końcowy fragment kodu, na którym pracuje dekorator wnętrz tworząc kolejne kompozycje.

Mieszkanie piekneMieszkanie = new MieszkanieNowe(); //tworzymy nasze piękne mieszkanie
piekneMieszkanie = new Jasne(piekneMieszkanie); //dekorujemy mieszkanie jasnymi ścianami
piekneMieszkanie = new ZTarasem(piekneMieszkanie); //dodajemy aranżację tarasu

Zwróć uwagę, że cały czas pracujemy na naszym pierwotnie utworzonym obiekcie i opakowujemy go kolejnymi nowymi obiektami. Nie zmieniamy typu obiektu ponieważ ciągle korzystamy z klasy Mieszkanie. Zarówno obiekt dekorowany piekneMieszkanie jak i obiekty dekorujące są tego samego typu co może wydawać się mało intuicyjne ale daje ogromne możliwości. Zapisane rozwiązanie można przedstawić graficznie w następujący sposób:

Aby zapewnić zgodność typów wszystkie klasy rozszerzają bazową klasę abstrakcyjną Mieszkanie:

package com.company;

public abstract class Mieszkanie {
    String opis; //zawiera opis dodawanej funkcjonalnosci

    public String getOpis() {
        return opis;
    }

    public abstract int indeksWartosci(); //zwraca wartosc wspolczynnika atrakcyjnosci mieszkania

}

Na tej podstawie tworzymy naszą klasę dekorowaną MieszkanieNowe(później można tworzyć podobnie inne klasy jak np. DomJednorodzinny, Szeregowiec itp.):

package com.company;

public class MieszkanieNowe extends Mieszkanie { //rozszerzamy klase Mieszkanie

    public MieszkanieNowe() {
        opis = "Mieszkanie z rynku pierwotnego";
    }

    @Override
    public int indeksWartosci() {
        return 50;
    }
}

Stworzyliśmy w ten sposób klasę dekorowaną która jest punktem wyjściowym całej kompozycji. Teraz przejdziemy do tworzenia dekoratorów a zaczniemy od tego, że jak wcześniej wspomniałem klasa dekorująca musi być tego samego typu co klasa dekorowana. Zatem stwórzmy klasę:

package com.company;

public abstract class Ozdoba extends Mieszkanie{
    public abstract String getOpis();
}

Tę klasę wykorzystamy do tworzenia właściwych klas dekorujących jak np:

package com.company;

public class Jasne extends Ozdoba {
    Mieszkanie mieszkanie;

    public Jasne(Mieszkanie mieszkanie) {
        this.mieszkanie = mieszkanie;
    }

    @Override
    public int indeksWartosci() {
        return mieszkanie.indeksWartosci() + 4;
    }

    @Override
    public String getOpis() {
        return mieszkanie.getOpis() + " + Sciany jasne";
    }
}
package com.company;

public class ZTarasem extends Ozdoba {
    Mieszkanie mieszkanie;

    public ZTarasem(Mieszkanie mieszkanie) {
        this.mieszkanie = mieszkanie;
    }

    @Override
    public int indeksWartosci() {
        return mieszkanie.indeksWartosci() + 10;
    }

    @Override
    public String getOpis() {
        return mieszkanie.getOpis() + " + Taras";
    }
}

Zwróć uwagę, że w konstruktorze obydwu klas przekazuję dotychczas istniejący obiekt mieszkania już jakoś udekorowaanego i w metodach indeksWartosci() oraz getOpis() dopisuję do poprzedniego obiektu nowe dane.

Właśnie stworzyliśmy prostą aplikację implementującą wzorzec dekorator. Na sam koniec zobaczmy jak zadziała nasza aplikacja po poskładaniu wszystkich klas w mainie:

package com.company;

public class Main {

    public static void main(String[] args) {
        Mieszkanie piekneMieszkanie = new MieszkanieNowe(); //tworzymy nasze piękne mieszkanie
        piekneMieszkanie = new Jasne(piekneMieszkanie); //dekorujemy mieszkanie jasnymi ścianami
        piekneMieszkanie = new ZTarasem(piekneMieszkanie); //dodajemy aranżację tarasu

        System.out.println("Indeks wartości:  " + piekneMieszkanie.indeksWartosci() + ", zawiera:  " + piekneMieszkanie.getOpis());
    }
}

Wyjście programu wygląda następująco:

Indeks wartości:  64, zawiera:  Mieszkanie z rynku pierwotnego + Sciany jasne + Taras

Process finished with exit code 0

Zauważ, że teraz bardzo łatwo dokładać można nowe klasy, zarówno dekorowane jak i dekorujące, ponieważ za każdym razem możemy korzystać bezpiecznie z wcześniej już napisanych klas bez obawy o ich wzajemną kompatybilność.

Na sam koniec przedstawię jeszcze definicję wzorca dekorator, która powinna być już dla Ciebie bardziej zrozumiała po przeczytaniu tego artykułu:

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

W powyższej definicji warto również zwrócić uwagę na słowo dynamiczne, ponieważ nic nie stoi na przeszkodzie aby naszemu dekoratorowi wnętrz w przyszłości zaimplementować rozwiązanie oparte na sztucznej inteligencji. Zbierało by ono informacje o właścicielu mieszkania i na tej podstawie w trakcie działania programu symulowałoby jak można by urządzić klientowi mieszkanie.

Mam nadzieję że mój artykuł przekonał Cię i dał zrozumienie co do wzorca dekorator, a jeśli masz uwagi to zapraszam do komentarza bądź do kontaktu poprzez formularz.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

W celu świadczenia usług na najwyższym poziomie stosuję pliki cookies, które będą zamieszczane w Państwa urządzeniu (komputerze, laptopie, smartfonie). W każdym momencie mogą Państwo dokonać zmiany ustawień Państwa przeglądarki internetowej i wyłączyć opcję zapisu plików cookies. Ze szczegółowymi informacjami dotyczącymi cookies na tej stronie można się zapoznać tutaj: View more
Ustawienia ciasteczek
Akceptuj
Blokuj
Polityka prywatności
Polityka prywatności & ciasteczka
Nazwa ciasteczka Aktywny

Polityka prywatności opisuje zasady przetwarzania przezE MNIE informacji na Twój temat, w tym danych osobowych oraz ciasteczek, czyli tzw. cookies.


1. Informacje ogólne

  1. Niniejsza polityka dotyczy Serwisu www, funkcjonującego pod adresem url: www.wojciechsiwek.pl
  2. Operatorem serwisu oraz Administratorem danych osobowych jest: Wojciech Siwek
  3. Adres kontaktowy poczty elektronicznej operatora: wojciech.siwek.programista@gmail.com
  4. Operator jest Administratorem Twoich danych osobowych w odniesieniu do danych podanych dobrowolnie w Serwisie.
  5. Serwis wykorzystuje dane osobowe w następujących celach:
    • Prowadzenie systemu komentarzy
    • Obsługa zapytań przez formularz
  6. Serwis realizuje funkcje pozyskiwania informacji o użytkownikach i ich zachowaniu w następujący sposób:
    1. Poprzez dobrowolnie wprowadzone w formularzach dane, które zostają wprowadzone do systemów Operatora.
    2. Poprzez zapisywanie w urządzeniach końcowych plików cookie (tzw. „ciasteczka”).

2. Wybrane metody ochrony danych stosowane przez Operatora

  1. Miejsca logowania i wprowadzania danych osobowych są chronione w warstwie transmisji (certyfikat SSL). Dzięki temu dane osobowe i dane logowania, wprowadzone na stronie, zostają zaszyfrowane w komputerze użytkownika i mogą być odczytane jedynie na docelowym serwerze.
  2. Hasła użytkowników są przechowywane w postaci hashowanej. Funkcja hashująca działa jednokierunkowo - nie jest możliwe odwrócenie jej działania, co stanowi obecnie współczesny standard w zakresie przechowywania haseł użytkowników.
  3. Operator okresowo zmienia swoje hasła administracyjne.
  4. W celu ochrony danych Operator regularnie wykonuje kopie bezpieczeństwa.
  5. Istotnym elementem ochrony danych jest regularna aktualizacja wszelkiego oprogramowania, wykorzystywanego przez Operatora do przetwarzania danych osobowych, co w szczególności oznacza regularne aktualizacje komponentów programistycznych.

3. Hosting

  1. Serwis jest hostowany (technicznie utrzymywany) na serwera operatora: NETMARK.

4. Twoje prawa i dodatkowe informacje o sposobie wykorzystania danych

  1. W niektórych sytuacjach Administrator ma prawo przekazywać Twoje dane osobowe innym odbiorcom, jeśli będzie to niezbędne do wykonania zawartej z Tobą umowy lub do zrealizowania obowiązków ciążących na Administratorze. Dotyczy to takich grup odbiorców:
    • operatorzy pocztowi
    • operatorzy systemu komentarzy
    • upoważnieni pracownicy i współpracownicy, którzy korzystają z danych w celu realizacji celu działania strony
  2. Twoje dane osobowe przetwarzane przez Administratora nie dłużej, niż jest to konieczne do wykonania związanych z nimi czynności określonych osobnymi przepisami (np. o prowadzeniu rachunkowości). W odniesieniu do danych marketingowych dane nie będą przetwarzane dłużej niż przez 3 lata.
  3. Przysługuje Ci prawo żądania od Administratora:
    • dostępu do danych osobowych Ciebie dotyczących,
    • ich sprostowania,
    • usunięcia,
    • ograniczenia przetwarzania,
    • oraz przenoszenia danych.
  4. Przysługuje Ci prawo do złożenia sprzeciwu w zakresie przetwarzania wskazanego w pkt 3.3 c) wobec przetwarzania danych osobowych w celu wykonania prawnie uzasadnionych interesów realizowanych przez Administratora, w tym profilowania, przy czym prawo sprzeciwu nie będzie mogło być wykonane w przypadku istnienia ważnych prawnie uzasadnionych podstaw do przetwarzania, nadrzędnych wobec Ciebie interesów, praw i wolności, w szczególności ustalenia, dochodzenia lub obrony roszczeń.
  5. Na działania Administratora przysługuje skarga do Prezesa Urzędu Ochrony Danych Osobowych, ul. Stawki 2, 00-193 Warszawa.
  6. Podanie danych osobowych jest dobrowolne, lecz niezbędne do obsługi Serwisu.
  7. W stosunku do Ciebie mogą być podejmowane czynności polegające na zautomatyzowanym podejmowaniu decyzji, w tym profilowaniu w celu świadczenia usług w ramach zawartej umowy oraz w celu prowadzenia przez Administratora marketingu bezpośredniego.
  8. Dane osobowe nie są przekazywane od krajów trzecich w rozumieniu przepisów o ochronie danych osobowych. Oznacza to, że nie przesyłamy ich poza teren Unii Europejskiej.

5. Informacje w formularzach

  1. Serwis zbiera informacje podane dobrowolnie przez użytkownika, w tym dane osobowe, o ile zostaną one podane.
  2. Serwis może zapisać informacje o parametrach połączenia (oznaczenie czasu, adres IP).
  3. Serwis, w niektórych wypadkach, może zapisać informację ułatwiającą powiązanie danych w formularzu z adresem e-mail użytkownika wypełniającego formularz. W takim wypadku adres e-mail użytkownika pojawia się wewnątrz adresu url strony zawierającej formularz.
  4. Dane podane w formularzu są przetwarzane w celu wynikającym z funkcji konkretnego formularza, np. w celu dokonania procesu obsługi zgłoszenia serwisowego lub kontaktu handlowego, rejestracji usług itp. Każdorazowo kontekst i opis formularza w czytelny sposób informuje, do czego on służy.

6. Logi Administratora

  1. Informacje zachowaniu użytkowników w serwisie mogą podlegać logowaniu. Dane te są wykorzystywane w celu administrowania serwisem.

7. Istotne techniki marketingowe

  1. Operator stosuje analizę statystyczną ruchu na stronie, poprzez Google Analytics (Google Inc. z siedzibą w USA). Operator nie przekazuje do operatora tej usługi danych osobowych, a jedynie zanonimizowane informacje. Usługa bazuje na wykorzystaniu ciasteczek w urządzeniu końcowym użytkownika. W zakresie informacji o preferencjach użytkownika gromadzonych przez sieć reklamową Google użytkownik może przeglądać i edytować informacje wynikające z plików cookies przy pomocy narzędzia: https://www.google.com/ads/preferences/

8. Informacja o plikach cookies

  1. Serwis korzysta z plików cookies.
  2. Pliki cookies (tzw. „ciasteczka”) stanowią dane informatyczne, w szczególności pliki tekstowe, które przechowywane są w urządzeniu końcowym Użytkownika Serwisu i przeznaczone są do korzystania ze stron internetowych Serwisu. Cookies zazwyczaj zawierają nazwę strony internetowej, z której pochodzą, czas przechowywania ich na urządzeniu końcowym oraz unikalny numer.
  3. Podmiotem zamieszczającym na urządzeniu końcowym Użytkownika Serwisu pliki cookies oraz uzyskującym do nich dostęp jest operator Serwisu.
  4. Pliki cookies wykorzystywane są w następujących celach:
    1. utrzymanie sesji użytkownika Serwisu (po zalogowaniu), dzięki której użytkownik nie musi na każdej podstronie Serwisu ponownie wpisywać loginu i hasła;
    2. realizacji celów określonych powyżej w części "Istotne techniki marketingowe";
  5. W ramach Serwisu stosowane są dwa zasadnicze rodzaje plików cookies: „sesyjne” (session cookies) oraz „stałe” (persistent cookies). Cookies „sesyjne” są plikami tymczasowymi, które przechowywane są w urządzeniu końcowym Użytkownika do czasu wylogowania, opuszczenia strony internetowej lub wyłączenia oprogramowania (przeglądarki internetowej). „Stałe” pliki cookies przechowywane są w urządzeniu końcowym Użytkownika przez czas określony w parametrach plików cookies lub do czasu ich usunięcia przez Użytkownika.
  6. Oprogramowanie do przeglądania stron internetowych (przeglądarka internetowa) zazwyczaj domyślnie dopuszcza przechowywanie plików cookies w urządzeniu końcowym Użytkownika. Użytkownicy Serwisu mogą dokonać zmiany ustawień w tym zakresie. Przeglądarka internetowa umożliwia usunięcie plików cookies. Możliwe jest także automatyczne blokowanie plików cookies Szczegółowe informacje na ten temat zawiera pomoc lub dokumentacja przeglądarki internetowej.
  7. Ograniczenia stosowania plików cookies mogą wpłynąć na niektóre funkcjonalności dostępne na stronach internetowych Serwisu.
  8. Pliki cookies zamieszczane w urządzeniu końcowym Użytkownika Serwisu wykorzystywane mogą być również przez współpracujące z operatorem Serwisu podmioty, w szczególności dotyczy to firm: Google (Google Inc. z siedzibą w USA), Facebook (Facebook Inc. z siedzibą w USA), Twitter (Twitter Inc. z siedzibą w USA).

9. Zarządzanie plikami cookies – jak w praktyce wyrażać i cofać zgodę?

  1. Jeśli użytkownik nie chce otrzymywać plików cookies, może zmienić ustawienia przeglądarki. Zastrzegamy, że wyłączenie obsługi plików cookies niezbędnych dla procesów uwierzytelniania, bezpieczeństwa, utrzymania preferencji użytkownika może utrudnić, a w skrajnych przypadkach może uniemożliwić korzystanie ze stron www
  2. W celu zarządzania ustawienia cookies wybierz z listy poniżej przeglądarkę internetową, której używasz i postępuj zgodnie z instrukcjami:
Zapisz ustawienia
Ustawienia ciasteczek