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
Coś jest w centrum Drogi Mlecznej. Czy to właśnie tego szukamy?
Radio nie do zdarcia: ponad 18,5 mln Polaków nie pozostawia złudzeń
AI upodobni się do... iOS lub Androida. Niewiarygodne, ale jednak
Pixel 10a zadebiutuje już za 2 tygodnie. Tak będzie wyglądał
Falcon 9 uziemiony. Mogło się skończyć tragedią
Lisa Su zapowiada nowego Xboxa. Znamy potencjalną datę premiery
Płacą w telefonach i telewizorach za korzystanie z AI. Całkiem odlecieli
Za ten owoc można dostać kilkadziesiąt tysięcy złotych. Dlaczego jest taki drogi? 
Keanu Reeves wraca na ekrany! Czy Apple powtórzy sukces Formuły 1?
Szybko poszło! "Reddit dla AI" już zaliczył koszmarny wyciek danych
Rewolucja na Marsie. Nie potrzebna już kontrola człowieka
Polowanie na użytkowników OtoMoto. Można stracić pieniądze
Najnowszy model Garmina w rekordowo niskiej cenie. Do tego Spotify za darmo
Nieoczywista złota kura Apple. Niedługo zarobią jeszcze więcej
T-Mobile odpala petardę - prawie tak tanio jak w Nju Mobile
Apple chce w tym roku zaszaleć. Szykujcie się na niespodzianki co tydzień
e-PIT odcina użytkowników. Dostęp do usługi zostanie wyłączony
Nowy Samsung Galaxy już niedługo. Czego możemy się spodziewać po nowym flagowcu Samsunga?
Początek kłopotów Muska. Policja wdarła się do biur
Samsung odcina flagowca. Ten smartfon już nie otrzyma aktualizacji
To by było na tyle, jeśli chodzi o możliwość ugody
Ocalić od zapomnienia
Ostatni kwant
ALH 84001 – meteoryt, o którym mówiono nawet w Białym Domu
HESS zarejestrował kosmiczny elektron o niespotykanej energii [Phys. Rev. Lett.]
Matka ciemnej materii – recenzja biografii “Vera Rubin. Życie”
Satelita, który zerwał się ze smyczy
Wiadomość od Carla Sagana do przyszłych eksploratorów Marsa
Ile najdłużej może trwać zaćmienie Słońca?
Nowa największa liczba pierwsza ma ponad 41 milionów cyfr [GIMPS]
30 lat konsoli PlayStation – Odcinek #130
Omawiamy serię The Walking Dead (gość: Stary Gracz)
Nikt nie potrzebuje cienkich smartfonów – Odcinek #129
To ostatni dzwonek na kolekcjonowanie gier i filmów
Najlepsza relacja z PGA 2025 (Poznań Game Arena)
Bumblebee wśród klawiatur. Marvo Meqa 80W – recenzja
Pierwsze spotkanie z Omoda 7 Super Hybrid
Logitech MX Master 4, Wednesday, 1670 sezon 2 – Odcinek #128
Tani pad, który chciał być jak DualSense. Test Monka Contra GT-96
Secret Service i prasa komputerowa w Polsce – Odcinek #127

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.