The Chain of Responsibility Pattern creates a Chain of recipient objects for a request. This avoids coupling between the sender and receiver of the request by giving multiple objects the opportunity to process the request.

In this pattern, each receiver typically contains a reference to the other receiver. If an object cannot handle the request, it passes the same request to the next recipient, and so on, until an object handles it.

This type of design pattern is behavioral.

Applicable scenario

The handler on the responsibility chain is responsible for processing the request, and the customer only needs to send the request to the responsibility chain without caring about the details of the request processing and the delivery of the request, so the responsibility chain decouples the sender of the request from the handler of the request.

  1. Multiple objects can handle the same request, and which object handles the request is automatically determined by the runtime.
  2. Submit a request to one of multiple objects without explicitly specifying the recipient.
  3. You can dynamically specify a set of objects to handle requests.

The sample application

JS event bubble Express, KOA middleware Onion model

  • Implementation of simple KOA middleware [Responsibility Chain Mode]
class Middleware {
    constructor() {
        this.middlewares = [];
    }
    use(fn) {
        if(typeoffn ! = ='function') {
            throw new Error('Middleware must be function, but get ' + typeof fn);
        } 
        this.middlewares.push(fn);
        return this;
    }
    compose() {
        const middlewares = this.middlewares;
        return dispatch(0);
        function dispatch(index) {
            const middleware = middlewares[index];
            if(! middleware) {return; }try{
                const ctx = {};
                const result = middleware(ctx, dispatch.bind(null, index + 1));
                return Promise.resolve(result);
            } catch(err) {
                return Promise.reject(err); }}}}/ / use
const middleware = new Middleware();
middleware.use(async (ctx, next) => {
    console.log(1);
    await next();
    console.log(2);
});
middleware.use(async (ctx, next) => {
    console.log(3);
    await next();
    console.log(4);
});
middleware.compose();// 1, 3, 4, 2
Copy the code

The advantages and disadvantages

Advantages:

  1. Reduce coupling. It decouples the sender and receiver of the request.
  2. Simplifies the object. The object does not need to know the structure of the chain.
  3. Enhanced flexibility in assigning responsibilities to objects. Responsibilities can be dynamically added or removed by changing members in the chain or reordering them.
  4. It is convenient to add new request handling classes.

Disadvantages:

  1. There is no guarantee that the request will be received.
  2. System performance will suffer, and it will be inconvenient to debug the code, which may cause circular calls.
  3. Runtime characteristics may not be easily observed, hindering debugging.

conclusion

The chain of responsibility pattern is a great way to manage code and reduce coupling between the object that initiates the request and the object that processes it. The number and order of nodes in the responsibility chain can vary freely, and we can determine which nodes are included in the chain at run time.

reference

  • JavaScript design patterns and development practices
  • Design Mode – Novice tutorial