Responsibility chain model of js design pattern

I Initial responsibility chain model

Definition: multiple objects have the opportunity to process the request, so as to avoid the relationship between the sender and receiver of the request. Connect the object into a chain and pass the request along a chain until an object processes it.

It may be a little obscure. Let's take a look at an example. For example, your mother asked you to go out to make soy sauce. At this time, my request is to buy a bottle of soy sauce. You will go out and buy soy sauce in the supermarket nearest to your home. If not, you will go to the next supermarket. When you know that a supermarket has bought soy sauce, you will end the transmission of this chain, The supermarket is equivalent to an object chain for processing requests. This is the responsibility chain model. We try to implement it in code.

II code implementation

Demand: let's take an example in life. There are three kinds of preferential activities for goods. The first is a 500 yuan deposit and a 100 yuan coupon, the second is a 200 yuan deposit and a 50 yuan coupon, and the third is no discount.

At this time, the first thing we think of is to use conditional branches to determine which preference belongs. Although the purpose can be achieved, the maintainability of the code is too low. We can use the responsibility chain mode to achieve it.

1. Flexible and separable responsibility chain nodes

Analysis: first, we package each offer separately to determine whether the request meets the offer conditions. If not, it will be passed down until the offer conditions are met.

        let order500 = function( orderType, pay, stock ) {
            if( orderType == 1 && pay == true) {
                console.log(" 500 A deposit of 100 yuan and a coupon of 100 yuan");
            }else{
                return 'nextSuccessor';
            }
        }

        let order200 = function( orderType, pay, stock ){

            if( orderType == 2 && pay == true ) {
                console.log(" 200 A deposit of 50 yuan and a coupon of 50 yuan");
            }else{
                return 'nextSuccessor';
            }
        }

        let orderNormal = function( orderType, pay, stock ) {
            if(stock > 0) {
                console.log("Ordinary purchase, no coupons");
            }else{
                console.log("Insufficient mobile phone inventory");
            }
        }

        // Packaging node
        let Chain = function( fn ){
            this.fn = fn;
            this.successor = null;
        }

        Chain.prototype.setNextSuccessor = function( successor ) {
            return this.successor = successor;
        }

        Chain.prototype.passRequest = function() {
            let ret = this.fn.apply(this, arguments);
            if( ret === "nextSuccessor") {
                return this.successor && this.successor.passRequest.apply(this.successor, arguments);
            }
            return ret;
        }

        // Create responsibility chain node

        let chainOrder500 = new Chain( order500 );
        let chainOrder200 = new Chain( order200 );
        let chainOrderNormal = new Chain( orderNormal );
        
        chainOrder500.setNextSuccessor( chainOrder200 ).setNextSuccessor(chainOrderNormal);


        chainOrder500.passRequest(1, true, 500);
        chainOrder500.passRequest(2, true, 500);

2. Asynchronous responsibility chain

Analysis: sometimes our requests may not be so smooth. For example, there may be a delay in getting the request data back. We judge whether to make another request according to the obtained data. Therefore, we need to set the initiative to transfer the request to the next node and implement it asynchronously.

        // Packaging node
        let Chain = function( fn ){
            this.fn = fn;
            this.successor = null;
        }

        Chain.prototype.setNextSuccessor = function( successor ) {
            return this.successor = successor;
        }

        Chain.prototype.passRequest = function() {
            let ret = this.fn.apply(this, arguments);
            if( ret === "nextSuccessor") {
                return this.successor && this.successor.passRequest.apply(this.successor, arguments);
            }
            return ret;
        }

        Chain.prototype.next = function() {
            return this.successor && this.successor.passRequest.apply( this.successor, arguments);
        }

        // Create responsibility chain node

        let fn1 = new Chain(()=>{
            console.log(1);
            return 'nextSuccessor';
        })
        let fn2 = new Chain(function(){
            console.log(2);
            let self = this;
            setTimeout(()=>{
                self.next();
            }, 2000);
        })

        let fn3 = new Chain(()=>{
            console.log(3);
        })

        fn1.setNextSuccessor( fn2 ).setNextSuccessor( fn3 );
        fn1.passRequest();

3. Implement responsibility chain with AOP

Analysis: although it is simple and ingenious to implement with AOP, stacking functions together also overlaps the scope of functions. If two days are too long, it will have a great impact on performance.

        Function.prototype.after = function( fn ) {
            let self = this;
            return function() {
                let ret = self.apply(this, arguments);
                if(ret === 'nextSuccessor') {
                    fn.apply( this, arguments );
                }
                return ret;
            }
        }

        let order = order500.after( order200 ).after( orderNormal );
        order(3, true, 500);

III summary

Advantages: 1 It decouples the complex relationship between the sender and receiver of the request

                   2. Each object can be split flexibly to control the entry and length of the request

Disadvantages: 1 Maybe most nodes in a delivery are only used as delivery, which is not very useful and causes performance loss

The responsibility chain pattern is applied appropriately in scope chain, prototype chain, or bubble event. The responsibility chain pattern can also be combined with the composite pattern to connect components and parent components, or improve the efficiency of composite objects.

Keywords: Javascript Front-end Design Pattern

Added by radley on Tue, 18 Jan 2022 12:47:42 +0200