Łańcuch zobowiązań

Łańcuch zobowiązań (ang. Chain of responsibility, niekiedy tłumaczony także jako Łańcuch odpowiedzialności[1]) – czynnościowy wzorzec projektowy, w którym żądanie może być przetwarzane przez różne obiekty, w zależności od jego typu.

Problem

Rozpatrzmy przykładowy komponent systemu, który przetwarza żądania przychodzące od innych komponentów. Każde żądanie ma określony typ, lub daje się zaklasyfikować do jakiejś kategorii. W zależności od typu, żądania mają być przetwarzane w odmienny sposób. Pragniemy zaimplementować mechanizm przetwarzania żądań, który umożliwiłby łatwe dodawanie w przyszłości obsługi nowych typów oraz ich usuwanie w razie potrzeby.

Budowa

Diagram klas wzorca Łańcuch zobowiązań

Wzorzec Łańcuch zobowiązań zakłada utworzenie oddzielnej klasy dla każdej procedury obsługi żądania dziedziczącej po pewnej klasie bazowej AbstrakcyjnaObsluga. Obiekt każdej z procedur może posiadać wskazanie na następnik, tworząc w ten sposób łańcuch procedur przetwarzania. Aby przetworzyć żądanie, wykonujemy metodę operacja() na pierwszym elemencie łańcucha. Jeśli nie potrafi on przetworzyć żądania, powinien przekazać je swojemu następnikowi:

public void operacja(żądanie: Żądanie)
{
   jeśli potrafimy obsłużyć dany typ żądania żądanie:
      obsłuż żądanie
   w przeciwnym wypadku:
      przekaż żądanie następnikowi
}

Konsekwencje użycia

Zalety:

  • elementy łańcucha mogą być dynamicznie dodawane i usuwane w trakcie działania programu[1],
  • zmniejszenie liczby zależności między nadawcą a odbiorcami,
  • implementacja pojedynczej procedury nie musi znać struktury łańcucha oraz innych procedur.

Wady:

  • wzorzec nie gwarantuje, że każde żądanie zostanie obsłużone[1],
  • śledzenie i debugowanie pracy działania łańcucha może być trudne[1].

Zastosowanie

Wzorzec znajduje zastosowanie wszędzie tam, gdzie mamy do czynienia z różnymi mechanizmami podobnych żądań, które można zaklasyfikować do różnych kategorii. Dodatkową motywacją do jego użycia są często zmieniające się wymagania.

Przykład użycia

Rozpatrzmy drzewo dokumentu (DOM). Każdy element może mieć elementy - dzieci, oraz ma swój element - rodzica w którym się zawiera (poza elementem głównym - rootem).

Użytkownik klika na któryś z elementów w drzewie. Jest to zarówno kliknięcie na ten element, jak i na elementy w których się znajduje ten element (rodziców - ponieważ znajdują się pod klikniętym elementem i kliknięcie może również dotyczyć ich). Elementy mogą mieć handler dla zdarzenia click - lub nie. Jeżeli obiekt posiada handler, obsługuje kliknięcie, i propagacja się kończy. Jeżeli handler uzna, że nie jest w stanie obsłużyć zdarzenia i zostanie wywołana odpowiednia metoda powodująca propagację wyżej, lub jeżeli obiekt nie posiada handlera, zdarzenie jest propagowane do rodzica klikniętego elementu. Cykl się powtarza dla rodzica - znowu, jeżeli potrafi on obsłużyć zdarzenie to propagacja się kończy, jeżeli nie, zdarzenie jest propagowane wyżej i wyżej, tak długo aż któryś z obiektów je obsłuży, lub propagacja osiągnie root element.

Zobacz też

Przypisy

  1. a b c d Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates: Head First Design Patterns Edycja Polska. Helion, 2005, s. 634-635. ISBN 83-7361-792-2. (pol.)

Linki zewnętrzne

Media użyte na tej stronie

Chain Of Responsibility classes pl.svg
Diagram klas wzorca Łańcuch Zobowiązań w języku polskim.