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 – Template Method
  • Programowanie
  • Wszystko

Wzorce projektowe – Template Method

Jakub Raczkowski 26 stycznia 2024

Zdziwilibyście się wiedząc jak często używana jest metoda szablonowa

Opisując wzorzec Polecenie (Command) zdarzyło mi się napomknąć, że „to taka ulepszona Strategia” – trochę bardziej skomplikowana, za to z dodatkowymi funkcjami. Idąc tym tokiem rozumowania, bohater dzisiejszego odcinka: Metoda szablonowa jest niczym więcej aniżeli połową Strategii.

Przypomnijmy: wzorzec Strategy pozwala nam np. tworzyć różne sposoby pozyskania danych. Jeśli tworzymy sobie taki agregator wyszukujący wszystkie oferty pracy na rynku to musi on korzystać z różnych stron pośredniczących: nofluffjobs, pracuj.pl, justjoin.it i tak dalej. Każdy z tych portali posługuje się innym API i musimy się do niego dostosować, aby dostać to co chcemy – każdy wymaga swojej własnej strategii. Nasz agregator łączy się najpierw z NoFluff używając do tego klasy o przykładowej nazwie NoFluffStrategy, potem korzysta z klasy PracujPlStrategy i tak, dalej aż w końcu wypluwa nam pełną listę wyszukanych ofert.

Wszystko wydaje się działać doskonale, czy więc ten mechanizm można jakoś ulepszyć?

Nie wiem, czy słyszeliście o pojęciu „decoupling” czyli usuwaniu duplikacji kodu. Ogólnie przyjętą zasadą i dobrym stylem programowania jest unikanie powtarzających się linijek kodu – eksportowanie ich do osobnej klasy/metody. Ta reguła ma wiele nazw, ale dla ułatwienia zapiszmy ją w taki sposób:

Przedkładaj ponowne wykorzystywanie kodu ponad jego duplikację.

Jeśli już programujecie to z pewnością zdajecie sobie sprawę jak upierdliwe są metody przyjmujące za parametr wartość String. Prawie za każdym razem, jeszcze zanim zaczniemy przetwarzać otrzymany tekst, musimy wpierw sprawdzić czy String nie jest null, tudzież nie jest pusty:

if (text == null 
	|| text.length == 0) 
	throw new InvalidArgumentException;

W końcu pojawiła się grupa programistów, która powiedziała „DOŚĆ!” i tak powstały biblioteki Apache Commons będące po prostu ulepszonymi standardowymi bibliotekami Javy, gdzie już nie musimy sprawdzać każdego Stringa (i wielu innych obiektów, framework jest większy niż myślicie) z osobna. Wszystko dzieje się w tle. Doskonały przykład decouplingu.

Te przyciski kuszą, ale musimy być silni. Źródło.

Wracając jednak do przykładu z agregatorem – z pewnością zauważycie, że w każdej strategii wiele elementów jest podobnych. A ostatecznie może wyjść tak, że jedna od drugiej różni się tylko wykorzystanym regexem oraz sposobem logowania. Aby usunąć tak powielony kod, a jednocześnie zachować pełnię kontroli nad algorytmem i utrzymać odpowiednią hermetyzację możemy skorzystać z Metody Szablonowej:

Wzorzec Metoda Szablonowa definiuje szkielet danego algorytmu w określonej metodzie, przekazując realizację niektórych jego kroków do klas podrzędnych. Wzorzec ten pozwala klasom podrzędnym na redefiniowanie pewnych kroków algorytmu, ale jednocześnie uniemożliwia zmianę jego struktury.

Rusz głową! Wzorce projektowe

Teraz, skoro już wiemy do czego służy, pozostaje nam tylko nauczyć się jak z tego wzorca korzystać.

Ale po kolei…

Ostatnim razem, przy okazji zabawy z Fasadą, pokazywałem wam jak wyglądają przygotowania do walki z perspektywy całej, choć początkującej drużyny. Czarodziej rzuca przyśpieszenie ruchów na wszystkich, Druid przyzywa zwierzaki, Łotrzyk ukrywa się w cieniu i tak dalej.

Są to raczej standardowe mechanizmy, które powielamy przed każdą potyczką. Czasami jednak musimy dorzucić coś ekstra aby skontrować skille konkretnego przeciwnika. Weźmy za przykład wampira.

Wampirzyca Bodhi – jeden z głównych bossów w Baldur’s Gate 2. Źródło.

W DnD wampir owszem jest trudnym zawodnikiem – ma niemało punktów życia, trudno go trafić, zadaje przyzwoite obrażenia… podobnie jak cała masa innych wrogów. To co czyni walkę z nim śmiertelnie niebezpieczną jest jego umiejętność wysysania poziomów.

Czyli np. my walczymy 12-poziomowym kapłanem, ale już jedno trafienie przez wampira zabiera nam 3 poziomy doświadczenia, a co za tym idzie zapominamy wartościowe czary, spadają nam maksymalne punkty zdrowia, zmniejsza się szansa na trafienie. Kolejne trzy udane ataki krwiopijcy i bohater ginie. Bez możliwości wskrzeszenia. Pozamiatane.

Jedynym sposobem by poradzić sobie z wampirami w walce bezpośredniej jest nałożenie na bohatera, który jest atakowany, czaru „Ochrona przed negatywną energią” który uniemożliwia wysysanie poziomów. Problem jednak jest taki, że to zaklęcie ma stosunkowo krótki czas trwania, dlatego rzucamy je tuż przed starciem.

A jak to wygląda w kodzie? Pełna wersja tutaj.

Oto nasza Metoda Szablonowa zaimplementowana w klasie abstrakcyjnej:

public final void prepareForBattle(){
            macroName(); //abstract
            summon(); 
            blessing();
            customDefensiveBuff(); //abstract
            extraSpell();
        }

Wywołuje ona 5 innych metod w Z GÓRY USTALONYM PORZĄDKU. Sekwencja jest kluczowa – najpierw przyzywamy summony, żeby załapały się na grupowe błogosławieństwo. Wspomniany wyżej czar ochrony przed negatywną energią rzucamy za to pod koniec makra, tak by starczył na jak najdłuższy czas.

Metoda szablonowa i uzupełniająca ją podklasa.

Tutaj widzicie co i dlaczego. Metoda prepareForBattle() jest zaimplementowana w klasie bazowej i ustawiona na finalną (final) tak, by podklasy nie mogły jej przesłaniać i kombinować z sekwencją zdarzeń.

Metoda summon() też jest zaimplementowana w super-klasie, ale może być przesłaniana. Co prawda przyzwanie powietrznego sługi sprawdza się w większości przypadków, ale czasem jest zbędne (bo np. nasze poprzednie summony wciąż żyją). Podobnie z błogosławieństwem – to podstawowy czar, jeśli dysponujemy np. Psalmem to lepiej przesłonić metodę.

customDefensiveBuff() jest metodą abstrakcyjną, czyli nasza podklasa jest ZOBOWIĄZANA ją zaimplementować. Będzie inna dla walki z nieumarłymi, a inna przy bitwie z czarnoksiężnikiem.

Na koniec zostaje nam extraSpell(), który jest już niby zaimplementowany w klasie bazowej, ale jest pusty. Dlaczego tak? Ponieważ jest nieobowiązkowy. Użytkownik ma możliwość dołożyć coś nowego do algorytmu, ale nie musi. Takie coś w świecie kodu nosi nazwę „haczyk”. Haczyków może nie być wcale, a może być wiele – nic nas nie ogranicza.

Trzy różne strategie oparte o nasz szablon

A na koniec pokaz możliwości każdej „strategii”. Wszystko działa jak należy, a do tego udało się uniknąć duplikacji kodu. Dziedziczenie użyte zgodnie z przeznaczeniem.

ITCandidateEvaluator

Z metody szablonowej jeszcze nie korzystałem, ale teraz – po poznaniu jej zasad oraz zalet – jestem pewien, że to się zmieni.

Już mówiłem, że w moim kolejnym projekcie pojawi się z góry określona hierarchia dziedziczenia. Na „górze” będzie abstrakcyjna klasa Kandydat, będą podklasy Junior, Mid, Senior, może coś jeszcze. Pewne elementy tych klas będą unikalne dla każdej z nich, ale już wiem, że jedna część będzie wspólna dla wszystkich: algorytm wyliczający końcowy wynik.

Nie będzie działał na zasadzie prostej średniej z punktów za poszczególne etapy, wzór będzie trochę bardziej skomplikowany. I może nieco inny dla każdej podklasy.

Wygląda to na wprost idealne miejsce na zastosowanie metody szablonowej – zamieszczę ją w abstrakcyjnej klasie Candidate, a następnie wykorzystam i uzupełnię poszczególne składowe w klasach dziedziczących. Do tej pory uważałem, że sprawę załatwię wzorcem Strategy, ale teraz widzę, że pojawiła się znacznie bardziej stylowa opcja.

Myślę, że na dziś wystarczy i jak zwykle dziękuję za poświęcony czas. Zapraszam do kolejnego odcinka gdzie zajmiemy się wzorcem „Iterator„.

Tags: design patterns programming

Continue Reading

Previous: Wzorce projektowe – Facade
Next: Wzorce projektowe – Iterator

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
AirPodsy 5 nieźle namieszały. Które słuchawki Apple warto teraz wybrać?
Apple Watch Ultra 4 bez fajerwerków. Czy mimo to warto go kupić?
Elon Musk zamówił LEGO i uruchomił lawinę złośliwości. Nie wierzcie mu na słowo
Oto tatuaż, który można włączyć i wyłączyć. Badacze stworzyli niemożliwe?
iPhone 18 Pro ma coś, czego wcześniej nie miał żaden iPhone
Używasz starej karty SD? To duży błąd
To jeden z największych problemów komputerów kwantowych. Jesteśmy krok bliżej przełomu
Pierwszy, poważny dowód na nieznaną planetę Układu Słonecznego? Oto on
Wegetarianie kontra mięsożercy. Badanie rozstrzyga kto łatwiej zbuduje mięśnie
Garmin Fenix 9 Pro na cenzurowanym. Deweloperzy narzekają na błędy
Darmowy upgrade telewizora. Włącz te 3 ustawienia
To może być największy serial sci-fi tego roku. Blade Runner 2099 coraz bliżej
LEGO szykuje prawdziwe perełki na 2027 rok. Niektóre mogą kosztować fortunę
Microsoft ubija kolejną funkcję znanej aplikacji
Parkside pomoże ogarnąć ogród i taras. Ceny zaczynają się od 24,99 zł
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
IceCube – miliard ton lodu, żeby dorwać neutrino
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
Wyglądają i grają jak premium, a kosztują ułamek tej ceny. Recenzja Baseus Inspire XH1
W co grać W PAŹDZIERNIKU? Nowe Star Wars Racer, powrót Gears of War
Team Xbox, team OLED i nowe Avengersy – Odcinek #138
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

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.