Chain of Responsibility

Design patterns / Behavioral patterns
image

//Handler: C has no classes, a rescuer is a struct,
//and a pointer to a function plays the virtual toHelp()
typedef struct Rescuer {
    struct Rescuer *next;
    int code;
    void (*toHelp)(void);
} Rescuer;

//HandleRequest()
void rescuerHelp(const Rescuer *rescuer, int code) {
    if (rescuer->code == code) {
        rescuer->toHelp();
    } else if (rescuer->next != nullptr) {
        rescuerHelp(rescuer->next, code);
    }
}

//ConcreteHandler: the initializer sets the code and the function
void firefighterToHelp(void) {
    printf("call firefighters\n");
}

Rescuer firefighterMake(Rescuer *next) {
    return (Rescuer){next, 1, firefighterToHelp};
}

//ConcreteHandler
void policeToHelp(void) {
    printf("call the police\n");
}

Rescuer policeMake(Rescuer *next) {
    return (Rescuer){next, 2, policeToHelp};
}

//ConcreteHandler
void ambulanceToHelp(void) {
    printf("call an ambulance\n");
}

Rescuer ambulanceMake(Rescuer *next) {
    return (Rescuer){next, 3, ambulanceToHelp};
}

Rescuer ambulance = ambulanceMake(nullptr);
Rescuer police = policeMake(&ambulance);
Rescuer firefighter = firefighterMake(&police);
rescuerHelp(&firefighter, 1);
//printed: call firefighters
rescuerHelp(&firefighter, 2);
//printed: call the police
rescuerHelp(&firefighter, 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.