Nie o takim makro dzisiaj mówimy. Źródło: www.miops.com
Słowo „makro” można rozumieć na kilka sposobów. Ten który nas dzisiaj interesuje oznacza skrypt pozwalający zrobić kilka rzeczy na raz. Odpowiednikiem takiego makra w świecie kodu jest wzorzec Fasada.
Chyba każdy z nas słyszał o makrach w popularnym pakiecie Office. Ich zadaniem jest przyspieszanie pracy – zamiast mozolnie wklepywać te same dane do n-tego dokumentu, wystarczy odpalić raz ustawione makro i cyk – gotowe. Czas na Pasjansa.
Teraz wyobraźcie sobie taką sytuację:
Robicie własną aplikację, która przyjmuje jakieś dane, umożliwia ich modyfikację i zapisuje rezultat do bazy danych. Jest tam przycisk „Zapisz i wyjdź”. Jak ma wyglądać logika tego komponentu? Co on ma tak dokładnie robić?
Cóż, przede wszystkim ma zapisywać dane. Jeśli np. edytujemy kartę pracownika to najpierw zamieniamy obiekt lokalny – w pamięci, a następnie przesyłamy to do bazy danych – jeśli tu wystąpi jakiś błąd to obsługujemy wyjątek. Jeżeli dane są wrażliwe to warto aby zostało to zalogowane do dziennika, a może nawet przyda się powiadomienie na skrzynkę mailową kierownika. Dopiero kiedy to wszystko zostanie załatwione można wywołać System.exit().
Sporo jak na jeden button, co nie?
Jak zaprogramować takie zależności? O ile wszystkie dotyczą jednego obiektu to można po prostu zaimplementować poniższą metodę w jego klasie:
public void saveAndQuit(){
this.addToTheList();
try{
upadeDatabase(list);
} catch (DatabaseException e){
log(e);}
notifyManager(info(this));
}
Tak to mniej więcej by wyglądało zakładając, że mówimy o obiektach tej samej klasy. Za to kiedy klas jest więcej to pracy przybywa. Fajnie by było gdyby zaimplementować jakiś mechanizm, który robiłby wszystko na raz. Gdyby…
…przysłaniał skomplikowany zestaw interfejsów swoim, prostym.

Wzorzec Fasada zapewnia jeden, zunifikowany interfejs dla całego zestawu interfejsów określonego podsystemu. Fasada tworzy nowy interfejs wysokiego poziomu, który powoduje, że korzystanie z całego podsystemu staje się zdecydowanie łatwiejsze.
Rusz głową! Wzorce projektowe
Ale po kolei…
Jak przygotować drużynę do trudnej potyczki?
Wszystko zależy od tego z kim zamierzamy walczyć. Jeśli z wysysającymi poziomy wampirami to bez czaru „Ochrona przed negatywną energią” rzuconego na każdego członka zespołu ani rusz. W przypadku otumaniających umbrowych kolosów zaklęcie zmieniamy na „Chaotyczne rozkazy”, a przy starciu z wrogimi magami „Osłona przed śmiercią”. Walcząc ze smokiem przyda się „Ochrona przed ogniem”, a z nieumarłym Liszem „Zwój ochrony przed magią”, który niweluje działanie jakichkolwiek zaklęć.

Powyższe to oczywiście podstawa, a jest tego znacznie więcej: aby przyśpieszyć postać, dodać jej siły lub zręczności, polepszyć rzuty obronne, ochronić przed obrażeniami fizycznymi, przywołać jakichś pomocników itd. Czasem samo przygotowanie może trwać tyle ile cała potyczka!
Na szczęście w niektórych grach można tworzyć sobie makra. Włączamy nagrywanie i rzucamy standardowe czary ochronne bądź używamy specjalnych umiejętności. Makro zapamiętuje co zostało użyte, przez kogo i na kogo. Za każdym kolejnym razem wystarczy już odpalić owe makro i poczekać chwilę na pełną gotowość bojową.
Możemy sami przygotować takie makro z użyciem wzorca Fasada. Pełny kod tutaj.

Mamy pełną drużynę: wojownik, łotrzyk, łowca, druid, kapłan i mag. Niektórzy mają po jednym skillu, inni po dwóch. Mogłem zrobić więcej, ale umówmy się, że to postacie na niskich poziomach i jeszcze wiele nie potrafią. Mimo to, jak dobrze policzymy, to i tak w konsoli jest ponad 20 linijek wyniku. Odpalanie tego za każdym razem ręcznie byłoby kłopotliwe.
Z pomocą przychodzi klasa Macro, która bierze te wszystkie klasy do swojego konstruktora, a jej jedyna metoda prepareForBattle() wywołuje żądane metody każdej postaci:
public void prepareForBattle(){
warrior.useSkill();
rogue.useSkill();
ranger.useSkill();
ranger.castSpell(warrior);
druid.castSpell(null);
druid.useSkill();
cleric.castSpell(warrior,rogue,ranger,druid,cleric,wizard);
wizard.castSpell(warrior,rogue,ranger,druid,cleric,wizard);
}
Jak sami widzicie nie jest to nic skomplikowanego, składnia wzorca jest może nawet łatwiejsza niż w Singletonie.
Facade to pojedyncza klasa, która nie potrzebuje niczego dziedziczyć, ani implementować żadnego interfejsu. Musi natomiast przyjmować do konstruktora wszystkie obiekty, których metody ma wywoływać.
ITCandidateEvaluator
Wzorzec jest sprytny, łatwy i przydatny. Lubię takie i jest spora szansa, że znajdzie się dla niego miejsce w moim kolejnym projekcie. Jeśli tylko zauważę, że pojawi się potrzeba „upieczenia nawet nie dwóch, ale kilku pieczeni na jednym ogniu” to z przyjemnością załatwię sprawę dobrze ustawioną fasadą.
Dziękuję za uwagę i zapraszam do następnego gdzie będziemy omawiać wzorzec Metoda Szablonowa (Template Method).