Skip to content

Witaj w Świecie Jutra!

  • Technologie jutra
  • Sprzęt jutra
  • Aplikacje jutra
  • Programowanie
  • Księga Drogi
  • Renowacja
  • Różności
  • Archiwum
  • Autor
  • Home
  • Wszystko
  • Wzorce projektowe – Decorator
  • Programowanie
  • Wszystko

Wzorce projektowe – Decorator

Jakub Raczkowski 19 stycznia 2024

Obrazek wygenerowany przez AI (Bing AI)

Historia lubi się powtarzać. Kiedy w ostatnim artykule opisywałem wam istotę wzorca „Obserwator”, byłem zaskoczony tym jak często z niego korzystałem nawet o tym nie wiedząc. Otwierając nowy rozdział Rusz Głową! i przechodząc do „Dekoratora” pomyślałem – „w końcu coś świeżego!”. Cóż…

Każda część w/w książki rozpoczyna się nakreśleniem tła fabularnego – przytacza się jakiś zagmatwany problem, a parę kartek dalej wchodzi omawiany wzorzec (cały na biało) i ratuje sytuację kilkoma celnie strzelonymi linijkami kodu.

I tak sobie czytam o kawiarence, która wpadła w tarapaty bo oferowała zbyt wiele różnych kaw do wyboru, a teraz programiści muszą tworzyć kolejne podklasy i podklasy podklas, a kod się duplikuje i dzieci płaczą. Sam się głowię – co teraz?! Gdzie ten Dekorator?!

Pojawiają się pierwsze linijki kodu i powoli do mnie dociera:

Hej, ja to już gdzieś widziałem!

A potem olśnienie i fala wstydu, bowiem tak właściwie to od Dekoratora zaczęła się moja przygoda z Javą! Nie zliczę ile razy wpisałem poniższą linijkę kodu rozwiązując zadania na CodeGym:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

Oficjalna definicja wzorca brzmi następująco:

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ść.

Rusz głową! Wzorce projektowe

Ach, dziedziczenie. Junior powiedziałby, że to lek na wszelkie bolączki. Senior: „sprawca mego upodlenia, obiekt mojej zemsty”.


Poprzedni wpis zakończyłem poradą:

„Przedkładaj kompozycję ponad dziedziczenie.”

Nie są to puste słowa. Unikanie dziedziczenia pozwala tworzyć bardziej elstyczny kod, odporny na działanie czasu i łatwiejszy w testowaniu. Musimy jednakowoż pamiętać, że superklasy i podklasy znajdują się w Javie nie bez powodu. Używanie ich z głową potrafi uprościć kod (chociaż kosztem jego „usztywnienia”). Dobry programista już na etapie projektowania zauważy moduły gdzie w przyszłości mogą pojawić się zmiany (czyli gdzie dziedziczenia należy unikać) oraz takie, które raczej będą stałe przez cały cykl rozwoju aplikacji. To tam właśnie nie ma co kombinować i można pozwolić sobie na kilka podklas.

Wzorzec „Dekorator” w tym wszystkim jest rozwiązaniem iście uniwersalnym – sprawdzi się zarówno przy zawiłej klasowej strukturze tzw. legacy code oraz tam gdzie zaczynamy od zera i już na starcie chcemy zadbać o porządną kompozycję.

Ale po kolei…

Najnudniejszą klasą w grach opartych na DnD jest według mnie bezapelacyjnie wojownik. Co oczywiście nie oznacza, że jest słaby, o nie! Dobrze wyszkolony fajter nie da sobie w kaszę dmuchać nawet wysokopoziomowym magom – spora pula punktów życia pozwala mu przetrwać więcej kul ognia niż przeciętny czarodziej potrafi wyciągnąć ze swojego rękawa. Z kolei świetne modyfikatory do rzutów obronnych sprawią, że nawet cała banda czarowników może mu wygrażać „Palcami Śmierci”, a i tak szansa na natychmiastowy zgon będzie minimalna.

Problem w tym, że gra wojownikiem jest zwyczajnie nudna. Każda potyczka wygląda tak samo:

  • kliknięcie na wroga i atak
  • jak pierwszy wróg padnie, kliknij na drugiego i atak
  • zapętl póki jeszcze jacyś wrogowie żyją

Szczególnie w porównaniu do czarodzieja, który raz, że musi przygotować zestaw czarów na daną okazję (inny na orków, inny na wampiry, inny na smoka) to jeszcze musi nimi żonglować w czasie potyczki kontrując to co robi przeciwnik.

  • wrogi mag rzuca: „Kamienna skóra”
  • ty rzucasz „Wyłom”, który ją zdejmuje
  • przydupasy gobliny biegną w twoją stronę
  • ty rzucasz „Kulę ognia” w sam środek grupy
  • wrogi mag rzuca „Chaotyczne rozkazy” i otumania twojego kolegę
  • ty strzelasz „Rozproszeniem magii”
  • …

I tak dalej. Dzieje się. Jest akcja.

Pewnym rozwiązaniem, które czyni prowadzenie wojownika ciekawszym jest dobór odpowiednich artefaktów czyli magicznych przedmiotów, które dysponują zaklęciami czarodzieja, tak, że nawet zwykły rębajło może z nich skorzystać.

Przykładami takich błyskotek są np. pierścień niewidzialności, buty szybkości lub płaszcz ochrony przed pociskami. Funkcji nie będę tłumaczył, bo nazwy mówią same za siebie. Pytanie tylko – jak to zakodować?

Jak (już w czasie działania programu) sprawić, żeby nasz wojownik, który nie potrafi czarować – nagle nabył tę umiejętność?

Spójrzmy na przykład. Cały kod znajdziecie tutaj.

Wojownik próbuje rzucić zaklęcie, ale nic się nie dzieje. Kod nie został zaimplementowany, bo i po co – WOJOWNICY NIE CZARUJĄ!

Ale, ale nic straconego. Wystarczy bowiem opakować (lub właśnie „udekorować„) obiekt wojownika w obiekt pierścienia niewidzialności i cyk! Nagle nasz woj zna magię!

Co ważne, takie opakowywanie nie musi być wcale jednokrotne. Równie dobrze możemy zrobić tak:

Wojownik założył wszystkie swoje artefakty i teraz zna już trzy czary.

Podsumowując. Konstrukcja Dekoratora jest całkiem prosta – mamy obiekt dekorowany i obiekty dekorujące, które w swoich konstruktorach muszą mieć parametr tożsamy z obiektem dekorowanym (ta sama klasa lub interfejs). W moim przypadku był to interfejs Spellcaster:

interface Spellcaster{
        void castSpell();
    }

    static class Warrior implements Spellcaster{
        @Override
        public void castSpell() {
            System.out.println("Wojownik rzuca czar:");
        }
    }

    static class InvisibilityRing implements Spellcaster{

        Spellcaster spellcaster;
		
        public InvisibilityRing(Spellcaster spellcaster) {
            this.spellcaster = spellcaster;
        }

        @Override
        public void castSpell() {
            spellcaster.castSpell();
            System.out.println("Niewidzialność.");
        }
    }

Czarownikiem jest zatem nawet sam pierścień, zauważcie jednak, że nie skorzystamy z niego jeśli nie założymy go na palec wojownika, który jest końcowym elementem układanki (tylko jego konstruktor nie wymaga dodatkowych parametrów).

ITCandidateEvaluator

Biorąc pod uwagę jak powszechny jest Dekorator nie mam absolutnie żadnych wątpliwości, że posłużę się nim w moim kolejnym projekcie. Na pewno przydarzy się to przy korzystaniu ze standardowych bibliotek Javy, np. podczas pracy z plikami:

BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(new File(...)));

Jeśli z kolei spytacie się mnie czy zamierzam tworzyć własne dekoratory to wydaje mi się, że nie zajdzie taka potrzeba. Mam tę komfortową sytuację, że program będę pisał „od zera”, więc moje klasy i ich obiekty już na starcie mogą mieć wszystkie wymagane metody.

Tym niemniej, będę pamiętał o dekoratorze i jeśli tylko pomoże mi on uniknąć niepotrzebnego dziedziczenia to nie zawaham się go użyć.

Dziękuję za uwagę i zapraszam do następnego odcinka – z wzorcem „Fabryka”.

Tags: design patterns programming

Continue Reading

Previous: Wzorce projektowe – Observer
Next: Wzorce projektowe – Abstract factory & Factory method

Related Stories

Mageege Moon104 – test niskoprofilowego mechanika
  • Sprzęt

Mageege Moon104 – test niskoprofilowego mechanika

11 marca 2025
Przebranżowienie cz.4
  • Programowanie

Przebranżowienie cz.4

27 lutego 2025
Smartfon Jutra
  • Sprzęt

Smartfon Jutra

15 lutego 2025

Ze świata

  • Antyweb
  • Kwantowo
  • Dwóch po dwóch
GTA VI to wisienka na torcie. Jesień na Xbox to wysyp innych hitów
Głośnik jak karton mleka. Takiej nietuzinkowej technologii nam trzeba
Prawdziwy wysyp hitów na PS5. Ta jesień przejdzie do historii
Przyspiesz Windows 11 bez pobierania żadnych apek
Użytkownicy Windowsa popełniają duży błąd. Ekspert tłumaczy zły nawyk
PKO BP odcina klientów od aplikacji. I to w środku tygodnia
Twój telewizor jest za jasny. Oto dlaczego powinieneś to naprawić
Nikt nie chce kupować komputerów. Ostatni kwartał był katasfrofą
Jak zeskanować kod QR na własnym ekranie telefonu — bez drugiego urządzenia
Pomidory na Księżycu? A to tylko początek
Apple TV nie zwalnia tempa. Te seriale zobaczymy jeszcze tej jesieni
Nowa opaska Google ma coś, czego brakuje wielu smartwatchom. Premiera tuż tuż
Kupujesz akumulator Parkside? Na te oznaczenia trzeba uważać
Internet dla studenta. Znalazłem najlepszy pakiet
Nowa funkcja w Mapach Google. Pokaże same hity
Pierwszy składak Apple w Plusie. Jest drogo...
Prościej, wygodniej i szybciej. Tak teraz pracuję na komputerze
ChatGPT wpadł w pułapkę? Jest kłopot z rozwiązaniem problemu Naviera-Stokesa
Za co naprawdę płacimy, kupując słuchawki premium? Wyjaśniamy na przykładzie Bowers & Wilkins Px7 S3
Recenzja Forever Ago. Piękna opowieść z nudną rozgrywką
O powstawaniu kamieni drogą doboru naturalnego
Świat upomina się o „właściwe” proporcje
Kosmiczna panorama i superkoronograf – co przyniesie nam Teleskop Nancy Roman?
O czym szepczą między sobą bozony Higgsa?
Wszechświat w trzech aktach – recenzja książki “Astronomia, kosmologia i astronautyka”
Wielka przerwa Wielkiego Zderzacza
A gdyby tak przeciąć foton na pół?
SpudCell – syntetyczna komórka, która udaje życie
Mega upał, omega manipulacja
Coraz więcej dowodów, coraz mniej pewności
Wyglądają i grają jak premium, a kosztują ułamek tej ceny. Recenzja Baseus Inspire XH1
WRZESIEŃ BĘDZIE MOCNY… Premiery gier, na które czekamy – Mamy do pogrania
Całkiem dobry film ten nowy Spider-Man: Brand New Day 🕷️ – No Movie Ci #18
Scyzorykon 2026, Galaxy Fold8 i całkiem nowy Spider-Man – Odcinek #137
Sprawdziliśmy Scyzorykon 2026 od środka!
Co się działo na Fantasy & Magic Con w Warszawie?
Porozmawiajmy o Steam Machine 🎮👀
Przedsprzedaż GTA VI, Stargate i gry, które paliły sprzęty – Odcinek #136
Relacja z CD-Action Expo 2026
Tańszy Game Pass, droższy Steam Deck i Internet 0202122 – Odcinek #135

To może cię zainteresować:

Mageege Moon104 – test niskoprofilowego mechanika
  • Sprzęt

Mageege Moon104 – test niskoprofilowego mechanika

11 marca 2025
Przebranżowienie cz.4
  • Programowanie

Przebranżowienie cz.4

27 lutego 2025
Smartfon Jutra
  • Sprzęt

Smartfon Jutra

15 lutego 2025
Czym jest Swagger?
  • Programowanie

Czym jest Swagger?

22 lipca 2024
  • Technologie jutra
  • Sprzęt jutra
  • Aplikacje jutra
  • Programowanie
  • Księga Drogi
  • Renowacja
  • Różności
  • Archiwum
  • Autor
Copyright © All rights reserved. | DarkNews by AF themes.