Przechadzka po szachownicy

Zadanie:
Odwiedź wszystkie pola szachownicy ruchem skoczka szachowego, odwiedzając każde pole tylko raz, zaczynając z a) rogu, b) jednego z pól środkowych, c) jednego z pól na brzegu, ale nie rogu.

Rozwiązanie:
Osoba (czyli Klient) sterująca skończkiem, zaczynającym z odpowiedniego miejsca zachownicy (czyli Odwiedzający), wykonuje ruchy skoczkiem po polach szachownicy (czyli Struktura Obiektów). W zależności od pola na których się znajdzie (czyli Elemencie Strukury) może wykonać zaakceptowane kroki – wycofać ruch (brak możliwości ruchu dalej, a są pola jeszcze bez odwiedzin), przejść do kolejnego wolnego pola, zakończyć przejście (wszystkie pola zostały odwiedzone). Próbowałem kiedyś to zadanie rozwiązać, zaczynając z różnych miejscach. Później spotkałem się z algorytmem dla programistów, który pozwala na określenie automatyczne takiej ścieżki.

Wzorzec Odwiedzający

Zaznaczone poprzez pogrubienie fragmenty odnoszą się do wzorca projektowego Odwiedzający (ang. Visitor). Przejście po Strukturze odbywa się tak, że najpierw następuje wysłane żądanie do Elementu Struktury z prośbą o akceptację Odwiedzającego. Następuje weryfikacja stanu. W momencie akceptacji, następuje polecenie odwiedzenia Elementu i wykonanie odpowiedniej operacji/polecenia.

Wzorzec jest przydatny, gdy chcemy przejść odpowiednią strukturę i wykonać dla każdego z elementów odpowiednią operację. W powyższym przykładzie obok zmiany stanu następuje wykonanie operacji wyboru kolejnego elementu, przejścia dalej lub wycofania, ponieważ stan wskazuje, że nie dane odwiedziny nie pozwolą na dalsze przejście. W takich sytuacjach zmiana operacji do wykonania powinna się odbywać bez wpływu na wszystkie elementy struktury. Załóżmy, że rozszerzamy strukturę o jeden poziom – np. szachownicę o jeden wiersz na dole, wtedy każdy z elementów struktury, na który ma ta zmiana wpływ, zostanie zmodyfikowany, a pozostałe nie ulegną zmianie.

Reklama

Znajomy błąd pełnomocnika

Siedzisz przed monitorem, uruchamiasz przeglądarkę i wpisujesz adres strony internetowej, klikasz enter i zamiast oczekiwanej zawartości strony pojawia się błąd:

„Proxy Error
The proxy server received an invalid response from an upstream server.
The proxy server could not handle the request GET /.
Reason: Error reading from remote server”

Brzmi znajomo? Myślę, że tak. Patrząc na stopień wykorzystania Internetu, połączeń i komunikacji elektronicznej taki błąd może się zdarzyć zawsze. Może to być podczas przeglądania Intranetu na domowym komputerze czy podczas szukania informacji w sieci wewnętrznej, mającej połączenie z Internetem.

Przyczyny błędu mogą być różne i na różnym etapie mogą nastapić – na serwerze sieci na przykład lokalnego dostawcy internetu, na serwerze firmy, który próbuje się dostać do danych wewnątrz, na serwerze obsługującym połączenia między siecią wewnętrzną a Internetem.

Cechą wspólną tych sytuacji jest to, że do pewnego serwera wysyłane jest żądanie, które on próbuje obsłużyć. A następnie ma miejsce komunikacja w drugą stronę. Poniższy przykładowy diagram przedstawia taką sytuację.

Diagram obrazuje także ideę wzorca projektowego Pełnomocnik (ang. proxy), który opiera się na założeniu, że między klientem a rzeczywistym obiektem znajduje się pełnomocnik. Pełnomocnik ten decyduje o udostępnieniu rzeczywistego obiektu (kontroluje dostęp do niego). Może mieć też charakter zabezpieczający, co jak najbardziej można sobie wyobrazić również w powyższych przykładach.

Nazwa „proxy”, pojawiająca się w powyższym komunikacie błędu, nie jest przypadkowa. Serwer zwracający ten błąd wskazuje o braku możliwości realizacji żądania albo o niedostępności rzeczywistego obiektu. Jest pełnomocnikiem zasobów dostępnych na danym serwerze lub w połączonej sieci.

Specjalistyczny pośrednik

Ponad roku, przy okazji omawiania wzorców „Fire and Forget” oraz „Request-Response posłużyłem się przykładem procesu ETL. Jednym z etapów realizacji tego procesu, jest wyciąganie (ang. Extract) danych. Wskazałem przykład zastosowania wzorca „Request-Response” (Pytanie – Odpowiedź) oparty na odpytywaniu bazy danych (dokładnie DBMS, tj. Systemu Zarządzania Bazą Danych) o dane/informacje/status i zwracanie przez nią stosownej informacji. Były to sprawdzenie dostępności bazy (DB), pytanie o wielkość danych (WD) i pobieranie kolejnych rekordów danych (DZ – dane zapytania). Takie działania mogą się odbywać poprzez bezpośrednie zapytania w języku SQL. Fragment oznaczony jako „bez wzorca” na diagramie poniżej przedstawia takie bezpośrednie odpytania.

Załóżmy jednak, że mamy odbytać kilka baz i powiązać dane ze sobą. Chcielibyśmy równocześnie uniknąć sytuacji namierzania się na każdą bazę osobno, identyfikowania jej strukury, a chcielibyśmy przekazać żądanie: sprawdź, pobierz, zapytaj. W takiej sytuacji między procesem Extract a poszczególnymi bazami danych można umieścić narzędzie pośredniczące, które wykona określone operacje i odpowiednio rozdzieli zadania po DBMS poszczególnych baz źródłowych.

W takim celu można zastosować wzorzec projektowy Fasada (ang. Facade), który zmniejszy liczbę połączeń i zależności między systemami. Wiąże się to utworzeniem „pośrednika” przyjmującego żądania i wysyłającego je do odpowiednich wykonawców. Sytuację taką prezentuje powyższy diagram w BMPN w części „wzorzec”.

Zaletą jest to, że mamy jeden interfejs, który można wykorzystać w różnych procesach, bez konieczności ingerowania w systemy źródłowe. Modyfikując połączenie między pośrednikiem a bazą (np. przeniesienie w inne miejsce, inna konfiguracja, sposób zapytania) modyfikujemy je tylko w jednym miejscu, bez konieczności zmiany procesów wywołujących. Takie rozwiązania są stosowane w implementacji systemów opartych o usługi (SOA).

Wzorcowa pizza

Wyobraźmy sobie, że jesteśmy w pizzerii i mamy ochotę zjeść pizzę. Nie wiemy jeszcze jaką, ale będzie to pizza. Można powiedzieć, że danie to jest pewien sposób abstrakcyjne, bliżej nieokreślone, do momentu, gdy zapoznamy się z menu i dowiemy się jakie są możliwości. Spośród rodzajów pizzy, np. Amerykańska, Wegetarianska, Hawajska, Rzeznicka itp., będziemy wybierać konkretną na podstawie jej składników, które w niej będą. Przeglądamy menu i decydujemy się na konkretne składniki – na przykład Ser, Szynka, Salami lub Ananans, Ser itd.

Wymienione składniki też są w pewien sposób abstrakcyjne, nie wiemy jak będą ułożone, ile ich będzie, jak będą duże, ale wiemy, że będzie to określony składnik.
Mamy więc od strony Klienta: wybraną pizzę składająca się z wymienionych składników.
Restauracja wie jaka pizza z jakich się składa elementów, ale dopiero w momencie przygotowania nastąpi ich wybór.

Powyższy przykład, opierając się na wyborze abstrakcyjnych składników z jednej strony, a dostarczenia konkretnych produktów z drugiej, można przedstawić za pomocą wzorca projektowego fabryka abstrakcyjna (ang. abstract factory).
Wzorzec ten składa się z elementów, zaprezentowanych na powyższym przykładowym diagramie UML:

  • Fabryka abstrakcyjna (ang. abstract factory) – interfejs dla klienta do wyboru konkretnych rodzajów pizzy. Na diagramie oznaczony jako „AF”.
  • Fabryka konkretna (ang. concrect factory) – określa elementy konieczne do stworzenia danej pizzy z elementów składowych. Na diagramie oznaczony jako „CF”.
  • Produkt abstrakcyjny (ang. abstract product) – interfejst dla klienta do wyboru rodzaju składników pizzy. Na diagramie oznaczony jako „AP”.
  • Produkt (ang. product) – konkretna realizacja oczekiwana przez klienta – dany składnik pizzy. Na diagramie oznaczony jako „P”.
  • Klient (ang. client) – używa powyższych elementów (wybiera pizzę, składniki). Na diagramie oznaczony jako „C”.

Klient inicjuje wybór pizzy, wybierając jej składniki, fabryka tworzy, w zależności od wybranej pizzy, odpowiednie zestawienie składników. Te zależności obrazują strzałki użytkowania (ang. uses) elementów na diagramie.