Łańcuch zobowiązań (Chain of responsibility)

Posted on by 0 comment

Kolejnym wzorcem, który wpadł w sidła cyklu wpisów o wzorcach projektowych, jest czynnościowy wzorzec projektowy (opisujące zachowanie) o ciekawej nazwie łańcuch zobowiązań, zwany także łańcuchem odpowiedzialności. Jego zasada działania jest stosunkowo prosta, za jego pomocą świetnie zaimplementowalibyśmy przerzucanie obowiązków między ludźmi w grupie, więcej w rozwinięciu artykułu.

Lista jednokierunkowa

Zacznę od przypomnienia czym jest lista kierunkowa.

Lista jednokierunkowa jest to struktura, w której każdy element zna adres następnego, o ile on istnieje. Charakterystycznymi cechami tej listy są szybkie operacje wstawiania oraz usuwania elementów.

Lista jednokierunkowa - Łańcuch zobowiązań (Chain of responsibility) wzorzec projektowy

Lista jednokierunkowa – Łańcuch zobowiązań (Chain of responsibility) wzorzec projektowy

 

Łańcuch zobowiązań

Filarem wzorca jest lista jednokierunkowa oraz klasa abstrakcyjna, która jest szablonem dla składników tej listy. Każda klasa, która dziedziczy po owej klasie abstrakcyjnej musi mieć zaimplementowaną metodę, która być może obsłuży odebrane zadanie. Dlaczego być może? Obiekt, który rozważa możliwość wykonania otrzymanego zadania, musi być na to gotowy, dlatego sprawdza, czy spełnia warunki, które upoważniają go do obsłużenia zadania. Jeśli je spełnia, to zajmuje się pracą, a jeśli nie, to próbuje zrzucić odpowiedzialność, zgodnie z zasadą działania listy kierunkowej na kolejnego, znanego mu przedstawiciela.

Diagram klas

Diagram klas - Łańcuch zobowiązań (Chain of responsibility) wzorzec projektowy

Diagram klas – Łańcuch zobowiązań (Chain of responsibility) wzorzec projektowy

Na powyższym diagramie klas, zidentyfikować można trzy grupy obiektów, są to:

  • Klient (client) – deklaruje żądanie wykonania jakiejś akcji, zleca jej wykonanie,
  • AbstrakcyjnaObsługa (handler) – definiuje interfejs dla właściwych wykonawców usługi, dostarcza mechanizm kolejki,
  • ImplementacjaObslugi (concrete handler)właściwy wykonawca, jeśli spełnia jego warunki obsługuje żądanie. Wie, czy istnieje następny wykonawca i posiada jego adres.

Diagram klas jest wiernym odzwierciedleniem opisu, jakim zdefiniowałem łańcuch zobowiązań.

Kod źródłowy

Szukając zastosowania dla tego wzorca, padło na warsztat samochodowy. Zainsynuujmy jego pracę Postanowiłem, że nasz abstrakcyjny warsztat, stosuje podział czynności na kilka grup. Niech przykładowo każdą grupę zadań obsługuje jeden pracownik, poniżej umieszczam plik Zadania.cs, w którym zdefiniowane są możliwe kategorie czynności do wykonania.

Postanowiłem, że rodzaje zadań zdefiniuje w typie wyliczeniowym enum.

W dalszym kroku zajmę się dostarczeniem klasy abstrakcyjnej Pracownik, która implementuje wzorzec łańcuch zobowiązań oraz jest szablonem dla każdego zatrudnionego w tym warsztacie.

Jak widzimy znajduje się tutaj właściwość kolejny, która będzie wskazywać na następnego pracownika oraz metoda UstawKolejnego, służąca do definiowania tej właściwości. Można dostrzec także funkcję WykonajZadanie, która będzie obsługiwać żądania klientów, a sama jej obecność tutaj, zmusza klasy dziedziczące do dostarczenia jej ciała.

Poniżej umieszczam kod trzech klas Kierownik, MechanikAudi, MechanikBMW, które dziedziczą po abstrakcyjnym szablonie Pracownik. Warto zwrócić uwagę na ciało wspomnianej chwilę temu metody WykonajZadanie, a szczególnie na instrukcję warunkową, która sprawdza, czy obiekt może obsłużyć zadanie. Jeśli nie, to w razie możliwości (jeśli taki istnieje, czyli referencja do następnego obiektu nie jest NULL) przekazuje ona odpowiedzialność na następny obiekt.

Kierownik.cs

MechanikAudi.cs

 MechanikBMW.cs

Zobaczmy teraz, jak to wszystko spisuje się w praktyce. Poniżej plik Program.cs z metodą Main.

Wyjście:

Głównym motorem, który inicjuje zadania jest tutaj pętla foreach. Zaletą, a zarazem i wadą tego wzorca projektowego łańcuch zobowiązań jest odseparowanie klienta od procesu wykonywania metody. Klient, tylko zleca zadanie i nie wie kto się jego podejmie. Jest to, de facto wada, ponieważ w tym wydaniu, klient nie jest nawet pewien, że ktokolwiek podejmie się obsługi jego żądania, tak samo będzie w przypadku wystąpienia błędów.

Podsumowanie

Patrząc poglądowo łańcuch zobowiązań, to elastyczny i przyjemny w implementacji wzorzec projektowy. Stosowany tam, gdzie żądania można z łatwością kategoryzować, dzieląc je tym samym na zróżnicowane grupy. Często stosuje się mechanizmy, które informują o poprawności wykonania żądania. Ponadto wzorzec, w zależności od potrzeb, po obsłużeniu  żądania, może dalej wędrować po kolejce, szukając kolejnego wykonawcy, lub tak jak w tym wpisie, zakończyć przeszukiwanie kolejki.

Wpis należy do serii postów o wzorcach projektowych.

Dodaj komentarz