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

Wzorce projektowe – Command

Jakub Raczkowski 23 stycznia 2024

Zdjęcie z gry Commandos 2

Wzorzec Strategy polega na stworzeniu interfejsu implementowanego przez klasy, które zajmują się tym samym ale w inny sposób. Np. gdy chcemy pobrać listy użytkowników z różnych stron, z różnym API. Ale, ale! Po co ja to powtarzam skoro Strategia była omawiana na samym początku serii, a dzisiaj zajmujemy się Poleceniem?

Czytając o wzorcu Command, miałem podobne przemyślenia jak zajmując się Abstract Factory. Deja vu. Początek wydawał się bowiem zupełnie taki jak we wspomnianym Strategy. Wszystkie trzy wzorce wymagają albo interfejsu, albo chociaż współdzielenia klasy dziedziczonej. Różnice tkwią w szczegółach oraz w przeznaczeniu każdego wzorca:

  • Strategii powinniśmy użyć, kiedy mamy kilka algorytmów do osiągnięcia tego samego rezultatu (wybieramy jeden, najlepszy w danej sytuacji)
  • Factory najlepiej sprawdza się przy masowym tworzeniu podobnych obiektów (wybieramy szablon produkcji i uruchamiamy fabrykę)
  • Command, trochę jak Strategy, też oferuje kilka algorytmów, ale każdy służy do czegoś innego, możemy je zakolejkować, a nawet cofnąć

Mówiąc krótko:

Wzorzec Polecenie to ulepszony wzorzec Strategia.

Polecenie – hermetyzuje żądania w postaci obiektów, co umożliwia paramateryzowanie różnych obiektów zróżnicowanymi żądaniami (takimi jak np. żądania kolejkowania lub rejestracji) oraz obsługiwania operacji, które można wycofać.

Rusz głową! Wzorce projektowe

Wyobraźcie sobie, że macie jakiś obiekt. Niech to będzie odpowiedzialny np. za odtwarzanie plików wideo: „Player”. Jak myślicie – ile powinien mieć metod aby spełniał swoją funkcję?

Pomyślmy: odtwórz plik, zatrzymaj, wznów, podgłośnij, ścisz, przewiń, cofnij, wyjdź… Póki co wyszło nam już osiem, a to przecież tylko niezbędne minimum. Aby wyróżnić się na tle innych podobnych aplikacji trzeba dodać kontrolę jasności, szybkości odtwarzania, zoom i masę innych. Tymczasem klasa obiektu rośnie i się komplikuje.

VLC player, jeden z najlepszych odtwarzaczy

A jeśli każda z tych metod byłaby odrębną klasą? Np. mamy klasę Ścisz, która ma tylko jedną metodę execute() która ścisza audio i nic więcej nie robi. Klasa musi oczywiście implementować odpowiedni interfejs (czyli Command) podobnie jak wszystkie inne klasy-polecenia. Wtedy wystarczy, że przed skorzystaniem ze ściszenia w Playerze, wyślemy temu obiektowi odpowiednie polecenie (setCommand()) które ustawia tę jedyną metodę klasy Player na wywoływanie execute() obiektu Ścisz.

Z jednej strony wydaje się to fajną sztuczką zapewniającą wysoką hermetyzację, ale z drugiej wygląda na prosty przepis aby utonąć w ilości tworzonych klas-komandosów (stąd grafika tytułowa, heh). Rozwiązanie jest owszem, fajne – ale tak jak z Singletonem, należy go używać z umiarem – wtedy kiedy rzeczywiście rozwiązuje jakiś problem.

Ale po kolei…

Parę odcinków temu, przy okazji omawiania wzorca Observer, tłumaczyłem wam zasadę działania znanego z DnD czaru Warunkowanie. Nie będę się powtarzał, ważne jest jednak to, że w Warunkowaniu umieszczaliśmy inny czar, który aktywował się w wybranej wcześniej sytuacji, na wybranym wcześniej celu.

Z jednej strony wygoda bo pełna automatyka, ale z drugiej – trochę nas to ograniczało, bo po inicjalizacji traciliśmy kontrolę nad zawartym zaklęciem. A co jeśli moglibyśmy sami wybrać czas i miejsce aktywacji?

Powiecie: głupota! Przecież tak właśnie działają zaklęcia bez żadnych warunkowań! Wybieram kulę ognia i strzelam w bandę goblinów dopiero gdy atakują kupą, wybieram kamienną skórę i rzucam na siebie dopiero kiedy dochodzi do walki w zwarciu.

A gdyby do takiego nie-automatycznego warunkowania można by włożyć więcej niż jeden czar?

O! I tu pojawia się potencjał! Jeśli mamy do czynienia z potężnym przeciwnikiem, to często już na starcie jest chroniony magią ochronną. Kamienna skóra blokuje obrażenia fizyczne, Ochrona przed żywiołami sprawia, że kula ognia też nie zada żadnych obrażeń. A Przyśpieszenie sprawi, że sam będzie atakował dwa razy szybciej.

W takich sytuacjach w Baldurze najlepiej sprawdzały się tzw. Sekwencery czyli właśnie ulepszone Warunkowania, zdolne zakolejkować i odpalić szybko jeden po drugim aż trzy zaklęcia. Moglibyśmy tam zatem umieścić kolejno Wyłom, Wrażliwość i Spowolnienie, aby usunąć z wroga wszelkie buffy.

Ale jak coś takiego wyglądałoby w kodzie (pełna wersja tutaj) wykorzystującym wzorzec Polecenie?

Na starcie potrzebujemy czarodzieja, któremu wystarczy jedna metoda.

static class Wizard{
        
        Commands currentCommand;
        
        void castSpell(Enemy enemy){
            System.out.print("Czarodziej rzuca czar: ");
            currentCommand.engage(enemy);
        }
}

Do tego interfejs implementowany przez różne polecenia (będące tutaj zaklęciami):

interface Commands{
        void engage(Enemy enemy);      
    }	
	
static class FireBall implements Commands{
      
        @Override
        public void engage(Enemy enemy) {
            System.out.println("Kula ognia.");
            enemy.hp -= 33;
        }

I już możemy zaobserwować efekty:

Czarodziej rzuca kulą ognia – Poleceniem w lodowego giganta.

Ale to nie wszystko, bo wcześniej wspomniałem:

„Command, podobnie jak Strategy, też oferuje kilka algorytmów, ale każdy służy do czegoś innego, możemy je zakolejkować, a nawet cofnąć.”

Cofnąć. Wydaje się trudne, a wystarczy do interfejsu Commands dodać drugą metodę, np. revert() która będzie odwrotnością tej pierwszej. Zatem jeśli Kula ognia zadaje 33 punkty obrażeń, to revert ma tyle samo przywracać:

public void revert() {
            enemy.hp += 33;
        }

Co fajne, kolejne polecenia możemy zakolejkować np. dodając je do stosu (Stack<>), a następnie wycofać wszystkie jednym ruchem, co w naszym wypadku byłoby swoistym wczytaniem stanu gry (loadGame()):

Wszystkie polecenia trafiają na stos, więc bardzo łatwo je odwrócić jedną metodą.

Rzeczona kolejka prowadzi nas też wprost do Sekwencera – zamiast wywoływać castSpell() możemy wrzucić wszystkie zaklęcia na stos (addToSequencer) i odpalić je razem metodą fireSequencer().

void fireSequencer(){
            System.out.println("Odpalono sekwencer zaklęć:");
            for (Commands command : allCommands) {
                command.engage(currentEnemy);
            }
        }
Możemy też zakolejkować polecenia bez wywoływania i odpalić je razem kiedy nam pasuje.

ITCandidateEvaluator

Teraz standardowe pytanie – czy widzę użycie wzorca Command w moim kolejnym projekcie?

Jeszcze nie, ale to się może zmienić.

Wydaje mi się, że Polecenie może wyjść w praniu przy refaktoryzacji kodu gdzieś pod koniec prac nad aplikacją. Np. jeśli zobaczę potrzebę umieszczenia przycisku „Cofnij” usuwającego ostatnio wprowadzoną zmianę. Albo gdy będę chciał hermetyzować niektóre metody danej klasy, tak by łatwo było mi je zmienić lub dodać kolejne w przyszłości (reguła: Otwarty/Zamknięty).

Samo kolejkowanie wprowadzonych poleceń też może się przydać w zakresie logowania informacji oraz błędów.

Na dzisiaj tyle i jak zwykle dziękuję za uwagę. Widzimy się już niedługo przy wzorcach Adaper oraz Fasada.

Tags: design patterns programming

Continue Reading

Previous: Wzorce projektowe – Singleton
Next: Wzorce projektowe – Adapter

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
Nowy zegar sięga do jądra atomu. Może pomóc szukać ciemnej materii
Apple pokazało dziwny film. 13 października wszystko stanie się jasne
Darmowe klony Photoshopa zalewają internet
Radio, muzyka i podcasty w GTA 6: Rockstar odsłania karty. Lista gwiazd robi wrażenie
Ekspres do kawy zapchał mu domowe Wi-Fi. 1 TB ruchu w zaledwie 10 dni!
Twój ChatGPT mocno Cię zaskoczy. Takich odpowiedzi się nie spodziewasz
Dziś wieczorem popatrz w górę. Tego spektaklu nie można przegapić
Masz Samsunga? Koniecznie włącz tę funkcję ochrony baterii
Teraz każdy stworzy własną grę. Google wypuszcza niezwykłe narzędzie
Nie wyrzucaj starych kabli USB-C. Oto 5 genialnych sposobów na ich drugie życie
Tajemnice filmu o Lady Pank i Janie Borysewiczu. Jest ukryte cameo
Chrome od teraz obsługuje JPEG XL. Zanim go użyjesz, sprawdź czym jest
Internet satelitarny w PKP Intercity. Rusza pilotaż
Allegro będzie wtrącać ci się w zakupy. Zaproponuje niższe ceny poza platformą
Samsung ogranicza... produkcję telefonów. Rynek tonie w absurdach
Amazon rozdaje 10 gier na PC. Wśród nich prawdziwe klasyki
Pixele wreszcie dogonią Apple? Ważna nowość
HUAWEI WATCH D3 – elegancki smartwatch czy certyfikowane urządzenie do pomiaru ciśnienia? Tak
Action rozpieszcza majsterkowiczów. Przydatne produkty za grosze
Koniec z łatwymi grami. Sony patentuje ciekawe rozwiązanie
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
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
Elite Dangerous. Gra, z której odchodzi się po cichu

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.