Chain of Responsibility

Design patterns / Behavioral patterns
image

import (
    "fmt"
)

//Rescuer is Handler
type Rescuer interface {
    Help(code int)
}

//chain keeps the next Handler and the code
//of the request that the Handler takes
type chain struct {
    next Rescuer
    code int
}

//handle is HandleRequest()
func (c chain) handle(code int, toHelp func()) {
    if c.code == code {
        toHelp()
    } else if c.next != nil {
        c.next.Help(code)
    }
}

//Firefighter is ConcreteHandler
type Firefighter struct {
    chain
}

func (f Firefighter) toHelp() {
    fmt.Println("call firefighters")
}

//Help passes the request to the chain
func (f Firefighter) Help(code int) {
    f.handle(code, f.toHelp)
}

//Police is ConcreteHandler
type Police struct {
    chain
}

func (p Police) toHelp() {
    fmt.Println("call the police")
}

//Help passes the request to the chain
func (p Police) Help(code int) {
    p.handle(code, p.toHelp)
}

//Ambulance is ConcreteHandler
type Ambulance struct {
    chain
}

func (a Ambulance) toHelp() {
    fmt.Println("call an ambulance")
}

//Help passes the request to the chain
func (a Ambulance) Help(code int) {
    a.handle(code, a.toHelp)
}

//Client
ambulance := Ambulance{chain{nil, 3}}
police := Police{chain{ambulance, 2}}
firefighter := Firefighter{chain{police, 1}}
firefighter.Help(1)
//printed: call firefighters
firefighter.Help(2)
//printed: call the police
firefighter.Help(3)
//printed: call an ambulance


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.