Wzorce projektowe – Łańcuch Odpowiedzialności

 lip, 09 - 2017   PHPWzorce Projektowe

wzorzez projektowy - łańcuch odpowiedzialności Łańcuch Odpowiedzialności to czynnościowy wzorzec projektowy, tworzący listę obiektów, które po kolei analizują żądanie i jeżeli potrafią je obsłużyć, to przystępują do procesu jego realizacji. W przeciwnym wypadku przekazują żądanie dalej, do kolejnego ogniwa w łańcuchu.

 

 

 

Charakterystyka wzorca łańcuch odpowiedzialności

 

Łańcuch Odpowiedzialności (Chain of Responsibility) nazywany jest również łańcuchem zobowiązań, ponieważ jego głównym zadaniem  jest przekazanie zobowiązania obsługi żądania na kolejny element w łańcuchu. Łańcuch takich obiektów tworzy listę jednokierunkową, w której odpowiedzialność za przetworzone żądanie spada na najlepiej przygotowany do tego obiekt.

Struktura kodu i zastosowanie opisywanego tu wzorca jest bardzo proste, co pokazuje poniższy diagram klas UML. Łańcuch odpowiedzialności składa się z obiektów (ogniw), które kolejno sprawdzają czy są w stanie przetworzyć przekazane im żądanie. Jeżeli tak to realizują zadanie i zwracają wynik, natomiast jeżeli nie, to przekazują żądanie dalej, do kolejnego ogniwa w łańcuchu. Każde z ogniw powinno wskazywać na koleje, oczywiście oprócz ostatniego, który oprócz kodu przetwarzającego żądanie, powinien obsłużyć sytuację, w której żaden z obiektów nie był w stanie zrealizować zadania.

 

łańcuch odpowiedzialności - diagram klas UML

 

 

Przykład zastosowania wzorca łańcuch odpowiedzialności – operacje na liczbach

 

Przykład w języku PHP, opisany poniżej, przedstawia sposób i implementacji i użycia wzorca Łańcuch Odpowiedzialności. Zadaniem skryptu będzie wykonanie prostych operacji matematycznych na dwóch liczbach.

Jako pierwszą napiszemy prostą klasę, która będzie reprezentowała nasze żądanie do przetworzenia. Klasa posiada właściwości przechowujące liczby, na których będzie wykonywana operacja oraz rodzaj tej operacji.

Teraz przystąpmy do napisania struktury programu, opartego na omawianym wzorcu. W pierwszej kolejności będzie to abstrakcyjna klasa reprezentująca abstrakcyjne ogniwo łańcucha. Klasa ta będzie rozszerzana w dalszej części przez konkretne ogniwa. Zawiera ona referencje do kolejnego ogniwa oraz metodę ustawiającą to ogniwo. Posiada również abstrakcyjną funkcję realizującą przekazywane żądanie. Metoda ta będzie implementowana w kolejnych elementach łańcucha.

 

 

Przystąpmy do napisania poszczególnych ogniw wzorca. Będą to klasy realizujące poszczególne działania matematyczne – dodawanie, odejmowanie, mnożenie i dzielenie. Jak widać  na poniższych listingach poszczególne klasy implementują metodę obsługującą żądanie, w której najpierw sprawdzają, czy są w stanie to zrobić. Jeżeli tak zwracają wynik, jeżeli nie, to wywołują tę samą metodę w kolejnym elemencie łańcucha.

Mając tak napisany skrypt, zadaniem klienta jest odpowiednie przygotowanie łańcucha, tzn. ustawienie kolejnych jego elementów, a następnie wywołania odpowiedniej metody na pierwszym obiekcie. W przypadku, gdy klient źle zbuduje łańcuch może dojść do sytuacji, gdzie żądanie nie zostanie w ogóle obsłużone.

Bardzo często zdarza się, że klient nie ma pojęcia, które ogniwo łańcucha zrealizuje zlecone zadanie. Wynik działania powyższego testu jest jak najbardziej poprawny.

 

Powyższy przykład można pobrać tutaj: numbers-calc

Przykład na GitHub: https://github.com/molitorys/design-patterns/tree/master/src/ChainOfResponsibility/Numbers

 

 

Podsumowanie

 

Zaletą stosowania wzorca łańcucha zobowiązań jest możliwość dynamicznego dodawania lub usuwania jego elementów. Ogniwa łańcucha są niezależne od siebie i nie muszą znać struktury łańcucha. Stosowanie wzorca zaleca się wszędzie tam, gdzie więcej niż jeden obiekt może obsłużyć żądanie, ale nie wiadomo z góry który z nich to zrobi oraz gdy obiekt obsługujący żądanie powinien być ustalony automatycznie.


Przeczytaj równierz