Autumn SALE
Łańcuch zobowiązań

Łańcuch zobowiązań w języku Ruby

Łańcuch zobowiązań to behawioralny wzorzec projektowy pozwalający przekazywać żądanie wzdłuż łańcucha potencjalnych obiektów obsługujących aż zostanie obsłużone.

W łańcuchu zobowiązań wiele obiektów może obsłużyć żądanie bez konieczności sprzęgania klas wysyłających je z konkretnymi klasami odbierającymi. Łańcuch można układać dynamicznie w trakcie działania programu z dowolnych obiektów obsługujących, wyposażonych w standardowy interfejs obsługi żądań.

Złożoność:

Popularność:

Przykłady użycia: Łańcuch zobowiązań jest rzadkim rozwiązaniem w programach napisanych w Ruby, gdyż ma sens tylko w tym kodzie, w którym występują łańcuchy obiektów.

Identyfikacja: Wzorzec można rozpoznać na podstawie obecności behawioralnych metod jednej grupy obiektów pośrednio wywołujących analogiczne metody w innych obiektach za pośrednictwem wspólnego interfejsu.

Przykład koncepcyjny

Poniższy przykład ilustruje strukturę wzorca Łańcuch zobowiązań ze szczególnym naciskiem na następujące kwestie:

  • Z jakich składa się klas?
  • Jakie role pełnią te klasy?
  • W jaki sposób elementy wzorca są ze sobą powiązane?

main.rb: Przykład koncepcyjny

# The Handler interface declares a method for building the chain of handlers. It # also declares a method for executing a request. class Handler # @abstract # # @param [Handler] handler def next_handler=(handler) raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end # @abstract # # @param [String] request # # @return [String, nil] def handle(request) raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end # The default chaining behavior can be implemented inside a base handler class. class AbstractHandler < Handler # @return [Handler] attr_writer :next_handler # @param [Handler] handler # # @return [Handler] def next_handler(handler) @next_handler = handler # Returning a handler from here will let us link handlers in a convenient # way like this: # monkey.next_handler(squirrel).next_handler(dog) handler end # @abstract # # @param [String] request # # @return [String, nil] def handle(request) return @next_handler.handle(request) if @next_handler nil end end # All Concrete Handlers either handle a request or pass it to the next handler # in the chain. class MonkeyHandler < AbstractHandler # @param [String] request # # @return [String, nil] def handle(request) if request == 'Banana' "Monkey: I'll eat the #{request}" else super(request) end end end class SquirrelHandler < AbstractHandler # @param [String] request # # @return [String, nil] def handle(request) if request == 'Nut' "Squirrel: I'll eat the #{request}" else super(request) end end end class DogHandler < AbstractHandler # @param [String] request # # @return [String, nil] def handle(request) if request == 'MeatBall' "Dog: I'll eat the #{request}" else super(request) end end end # The client code is usually suited to work with a single handler. In most # cases, it is not even aware that the handler is part of a chain. def client_code(handler) ['Nut', 'Banana', 'Cup of coffee'].each do |food| puts "\nClient: Who wants a #{food}?" result = handler.handle(food) if result print " #{result}" else print " #{food} was left untouched." end end end monkey = MonkeyHandler.new squirrel = SquirrelHandler.new dog = DogHandler.new monkey.next_handler(squirrel).next_handler(dog) # The client should be able to send a request to any handler, not just the first # one in the chain. puts 'Chain: Monkey > Squirrel > Dog' client_code(monkey) puts "\n\n" puts 'Subchain: Squirrel > Dog' client_code(squirrel) 

output.txt: Wynik działania

Chain: Monkey > Squirrel > Dog Client: Who wants a Nut? Squirrel: I'll eat the Nut Client: Who wants a Banana? Monkey: I'll eat the Banana Client: Who wants a Cup of coffee? Cup of coffee was left untouched. Subchain: Squirrel > Dog Client: Who wants a Nut? Squirrel: I'll eat the Nut Client: Who wants a Banana? Banana was left untouched. Client: Who wants a Cup of coffee? Cup of coffee was left untouched. 

Łańcuch zobowiązań w innych językach

Łańcuch zobowiązań w języku C# Łańcuch zobowiązań w języku C++ Łańcuch zobowiązań w języku Go Łańcuch zobowiązań w języku Java Łańcuch zobowiązań w języku PHP Łańcuch zobowiązań w języku Python Łańcuch zobowiązań w języku Rust Łańcuch zobowiązań w języku Swift Łańcuch zobowiązań w języku TypeScript