![Chain of Responsibility](/images/patterns/cards/chain-of-responsibility-mini.png?id=36d85eba8d14986f053123de17aac7a7)
Chain of Responsibility em Ruby
O Chain of Responsibility é um padrão de projeto comportamental que permite passar a solicitação ao longo da cadeia de handlers em potencial até que um deles lide com a solicitação.
O padrão permite que vários objetos tratem a solicitação sem acoplar a classe remetente às classes concretas dos destinatários. A cadeia pode ser composta dinamicamente em tempo de execução com qualquer handler que siga uma interface de handler padrão.
Complexidade:
Popularidade:
Exemplos de uso: O padrão Chain of Responsibility não é um padrão frequente em um programa Ruby, pois é relevante apenas quando o código opera com cadeias de objetos.
Identificação: O padrão é reconhecível pelos métodos comportamentais de um grupo de objetos que indiretamente chamam os mesmos métodos em outros objetos, enquanto todos os objetos seguem a interface comum.
Exemplo conceitual
Este exemplo ilustra a estrutura do padrão de projeto Chain of Responsibility. Ele se concentra em responder a estas perguntas:
- De quais classes ele consiste?
- Quais papéis essas classes desempenham?
- De que maneira os elementos do padrão estão relacionados?
main.rb: Exemplo conceitual
# 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: Resultados da execução
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.