Chain of Responsibility

Design patterns / Behavioral patterns
image

-- ConcreteHandlers: a handler answers its own
-- request and returns nothing for the others
local function firefighter(code)
  if code == 1 then
    return "call firefighters"
  end
end

local function police(code)
  if code == 2 then
    return "call the police"
  end
end

local function ambulance(code)
  if code == 3 then
    return "call an ambulance"
  end
end

-- The chain is an array: the handlers
-- are asked in this order
local rescuers = {firefighter, police, ambulance}

-- HandleRequest(): the first answer ends the walk
local function help(code)
  for _, rescuer in ipairs(rescuers) do
    local answer = rescuer(code)
    if answer then
      return answer
    end
  end
  return "nobody handles code " .. code
end

-- Client
local answer1 = help(1)
-- answer1 = call firefighters
local answer2 = help(2)
-- answer2 = call the police
local answer3 = help(3)
-- answer3 = call an ambulance
local answer9 = help(9)
-- answer9 = nobody handles code 9

print("answer1 = " .. answer1)
print("answer2 = " .. answer2)
print("answer3 = " .. answer3)
print("answer9 = " .. answer9)


Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
Read more

The problem. A support service receives requests of different sizes. A small one goes to an assistant, a larger one to a manager, a very large one to a director. If the code that sends a request had to choose the receiver itself, it would have to know every receiver and every rule. Each new receiver would mean a change in the sender.

The idea. The receivers, called handlers, are placed in a fixed order: the chain. The sender gives a request only to the first handler. Each handler checks whether the request is its own. If it is, the handler does the work, and the request goes no further. If it is not, the handler passes the request to the next one. The sender does not know which handler will answer, or whether any will.

How to read the example. Several handlers are joined into a chain. Each one decides by its own rule whether a request is its own. The client code sends several requests, always to the start of the chain. Each request moves along the chain until a handler accepts it. In most languages each handler keeps a link to the next one; in some, the chain is a simple list checked in order. Some examples also send a request that no handler accepts, and the output reports it.

When to use it. Use a chain when several objects may handle a request, and their set or their order may change. Do not use it when the receiver is always the same: a direct call is simpler and easier to follow.

A common mistake. Forgetting the end of the chain. A request that no handler accepts is then lost without any message. Decide what happens at the end: an error, a default handler or a clear report.