Cadeia Javascript de padrão de responsabilidade

Cadeia de Padrões de Responsabilidade na Realidade

Exemplos do padrão Cadeia de Responsabilidade não são difíceis de encontrar na realidade.A seguir estão dois cenários comuns relacionados ao padrão Cadeia de Responsabilidade.

❏ Se você conseguir entrar tranquilamente no ônibus na hora do rush da manhã, estima-se que terá um dia muito feliz. Como há muitas pessoas no ônibus, muitas vezes não consigo encontrar o condutor depois de entrar no ônibus, então tenho que passar a moeda de dois yuans para a frente. A menos que você tenha a sorte de que a primeira pessoa à sua frente seja o condutor, sua moeda geralmente precisa passar por N mãos antes de finalmente chegar ao condutor.

❏ Se você conseguir entrar tranquilamente no ônibus na hora do rush da manhã, estima-se que terá um dia muito feliz. Como há muitas pessoas no ônibus, muitas vezes não consigo encontrar o condutor depois de entrar no ônibus, então tenho que passar a moeda de dois yuans para a frente. A menos que você tenha a sorte de que a primeira pessoa à sua frente seja o condutor, sua moeda geralmente precisa passar por N mãos antes de finalmente chegar ao condutor.

Tome como exemplo os cupons de pedidos:

Suponha que somos responsáveis ​​por um site de comércio eletrônico que vende telefones celulares. Após duas rodadas de reservas com um depósito de 500 yuan e um depósito de 200 yuan (o pedido foi gerado neste momento), chegamos ao estágio de compra oficial.

A empresa tem certas políticas preferenciais para usuários que pagaram um depósito. Após a compra oficial, os usuários que pagaram um depósito de 500 yuans receberão um cupom de 100 yuans no shopping, os usuários com um depósito de 200 yuans receberão um cupom de 50 yuans e os usuários que não pagaram um depósito antes podem entre apenas no modo de compra normal , ou seja, não há cupons e não há garantia de que você poderá comprá-lo quando o estoque for limitado.

Nossa página de pedido é um modelo que o PHP gera e, no início do carregamento da página, o PHP passa alguns campos para a página.
❏ orderType: Indica o tipo de pedido (usuário de depósito ou comprador comum). é um comprador comum.

❏ pagar: indica se o usuário pagou o depósito, o valor é verdadeiro ou falso, embora o usuário tenha feito um pedido com um depósito de 500 yuan, se não pagou o depósito, ele só pode ser rebaixado para a compra normal modo agora.

❏ estoque: indica o estoque atual de telefones celulares usados ​​para compras comuns. Os usuários que pagaram um depósito de 500 yuan ou 200 yuan não estão sujeitos a essa restrição.

nenhum modelo de responsabilidade

Se você usar o padrão de cadeia de responsabilidade, poderá escrevê-lo assim:

        var order = function( orderType, pay, stock ){
    
    
            if ( orderType === 1 ){
    
            // 500元定金购买模式
              if ( pay === true ){
    
        // 已支付定金
                  console.log( '500元定金预购,得到100优惠券’ );
              }else{
    
        // 未支付定金,降级到普通购买模式
                  if ( stock > 0 ){
    
        // 用于普通购买的手机还有库存
                      console.log( ’普通购买,无优惠券’ );
                  }else{
    
    
                      console.log( '手机库存不足' );
                  }
              }
            }

            else if ( orderType === 2 ){
    
         // 200元定金购买模式
              if ( pay === true ){
    
    
                  console.log( '200元定金预购, 得到50优惠券' );
              }else{
    
    
                  if ( stock > 0 ){
    
    
                      console.log( '普通购买, 无优惠券' );
                  }else{
    
    
                      console.log( '手机库存不足' );
                  }
              }
            }

            else if ( orderType === 3 ){
    
    
              if ( stock > 0 ){
    
    
                  console.log( '普通购买, 无优惠券' );
              }else{
    
    
                  console.log( '手机库存不足' );
              }
            }
        };

        order( 1 , true, 500);  // 输出: 500元定金预购, 得到100优惠券

Embora o projeto atual esteja funcionando normalmente, o próximo trabalho de manutenção é sem dúvida um pesadelo.

Refatore seu código com o padrão Chain of Responsibility

Primeiro, você precisa reescrever as funções do nó que representam os três modos de compra. Concordamos que, se um nó não puder processar a solicitação, ele retornará uma string específica 'nextSuccessor' para indicar que a solicitação precisa ser repassada:(Atualmente você pode lidar com isso via booleanos)

        var order500 = function( orderType, pay, stock ){
    
    
            if ( orderType === 1 && pay === true ){
    
    
              console.log( '500元定金预购,得到100优惠券’ );
            }else{
    
    
              return 'nextSuccessor';    // 我不知道下一个节点是谁,反正把请求往后面传递
            }
        };

        var order200 = function( orderType, pay, stock ){
    
    
            if ( orderType === 2 && pay === true ){
    
    
              console.log( '200元定金预购,得到50优惠券’ );
            }else{
    
    
              return 'nextSuccessor';    // 我不知道下一个节点是谁,反正把请求往后面传递
            }
        };

        var orderNormal = function( orderType, pay, stock ){
    
    
            if ( stock > 0 ){
    
    
              console.log( ’普通购买,无优惠券’ );
            }else{
    
    
              console.log( ’手机库存不足’ );
            }
        };

Em seguida, precisamos envolver a função no nó da cadeia de responsabilidade. Definimos um construtor Chain. O parâmetro passado na nova Chain é a função que precisa ser agrupada. Ao mesmo tempo, também possui um atributo de instância this.successor , que representa a função na cadeia.próximo nó. Além disso, existem duas funções no protótipo do Chain, e suas funções são as seguintes:

        // Chain.prototype.setNextSuccessor  指定在链中的下一个节点
        // Chain.prototype.passRequest  传递请求给某个节点

        var Chain = function( fn ){
    
    
            this.fn = fn;
            this.successor = null;
        };

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

        Chain.prototype.passRequest = function(){
    
    
            var ret = this.fn.apply( this, arguments );

            if ( ret === 'nextSuccessor' ){
    
    
                return this.successor && this.successor.passRequest.apply( this.successor, arguments );
            }

            return ret;
        };

Agora empacotamos as três funções de ordem como nós da cadeia de responsabilidade:

        var chainOrder500 = new Chain( order500 );
        var chainOrder200 = new Chain( order200 );
        var chainOrderNormal = new Chain( orderNormal );

Em seguida, especifique a ordem dos nós na cadeia de responsabilidade:

        chainOrder500.setNextSuccessor( chainOrder200 );
        chainOrder200.setNextSuccessor( chainOrderNormal );

Por fim, passe a solicitação para o primeiro nó:

        chainOrder500.passRequest( 1, true, 500 );    // 输出:500元定金预购,得到100优惠券
        chainOrder500.passRequest( 2, true, 500 );    // 输出:200元定金预购,得到50优惠券
        chainOrder500.passRequest( 3, true, 500 );    // 输出:普通购买,无优惠券
        chainOrder500.passRequest( 1, false, 0 );     // 输出:手机库存不足

Através da melhoria, podemos adicionar, remover e modificar a ordem dos nós na cadeia de forma livre e flexível. Se um dia o operador do site apresentar um depósito de 300 yuans para apoiar a compra, podemos adicionar um nó na cadeia:

        var order300 = function(){
    
    
            // 具体实现略
        };

        chainOrder300= new Chain( order300 );
        chainOrder500.setNextSuccessor( chainOrder300);
        chainOrder300.setNextSuccessor( chainOrder200);

cadeia assíncrona de responsabilidade

Deixamos que cada função de nó retorne sincronizadamente um valor específico "nextSuccessor" para indicar se deve passar a solicitação para o próximo nó. No desenvolvimento real, geralmente encontramos alguns problemas assíncronos. Por exemplo, precisamos iniciar uma solicitação assíncrona ajax na função do nó, e o resultado retornado pela solicitação assíncrona pode determinar se devemos continuar com passRequest na cadeia de responsabilidade.

Neste momento, não faz sentido para a função do nó retornar "nextSuccessor" de forma síncrona, então precisamos adicionar um método de protótipo Chain.prototype.next à classe Chain, indicando que a solicitação é passada manualmente para o próximo nó da cadeia de responsabilidade:

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

Vejamos um exemplo de uma cadeia de responsabilidade assíncrona:

        var fn1 = new Chain(function(){
    
    
            console.log( 1 );
            return 'nextSuccessor';
        });

        var fn2 = new Chain(function(){
    
    
            console.log( 2 );
            var self = this;
            setTimeout(function(){
    
    
              self.next();
            }, 1000 );
        });

        var fn3 = new Chain(function(){
    
    
            console.log( 3 );
        });

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

Agora temos uma cadeia especial, a solicitação é passada entre os nós da cadeia, mas o nó tem o direito de decidir quando passar a solicitação para o próximo nó. É concebível que, com a cadeia de responsabilidade assíncrona mais o modo de comando (encapsulando a solicitação ajax em um objeto de comando, consulte o Capítulo 9 para obter detalhes), possamos criar facilmente uma biblioteca de fila ajax assíncrona.

Prós e contras do padrão Cadeia de Responsabilidade

Conforme mencionado anteriormente, a maior vantagem do modelo de cadeia de responsabilidade é que ele desacopla o relacionamento complexo entre o remetente da solicitação e os receptores N. Como você não sabe qual nó na cadeia pode lidar com sua solicitação, basta enviar o pedido Basta passá-lo para o primeiro nó,
insira a descrição da imagem aqui
insira a descrição da imagem aqui

vantagem

Após melhoria com o modelo da cadeia de responsabilidade: No exemplo da loja de celulares, fomos obrigados a manter uma enorme função cheia de declarações condicionais de ramificação, no exemplo, apenas uma declaração de log foi impressa durante o processo de compra. Na verdade, no desenvolvimento real, há mais coisas a fazer aqui, como exibir diferentes prompts de camada flutuante de acordo com o tipo de pedido, renderizar diferentes nós de interface do usuário, combinar diferentes parâmetros e enviá-los para diferentes cgis, etc. Depois de usar o modo de cadeia de responsabilidade, cada pedido tem sua própria função de processamento sem afetar um ao outro.

deficiência

O modo Cadeia de Responsabilidade adiciona alguns objetos nodos no programa. Talvez em um determinado processo de entrega de requisição, a maioria dos nodos não desempenhe um papel substantivo. Sua função é apenas deixar a requisição passar. Do ponto de vista do desempenho, nós Para evitar perda de desempenho causada por cadeia de responsabilidade muito longa.

Realize a Cadeia de Responsabilidade com AOP

unction.prototype.after, de forma que quando a primeira função retornar 'nextSuccessor', a requisição será passada para a próxima função. Quer ela retorne a string 'nextSuccessor' ou false é apenas um contrato. Claro, também podemos deixar a função Return false para repassar a requisição, a string 'nextSuccessor' foi escolhida por parecer mais expressiva para nossos propósitos.

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

              return ret;
            }
        };

        var order = order500yuan.after( order200yuan ).after( orderNormal );

        order( 1, true, 500 );    // 输出:500元定金预购,得到100优惠券
        order( 2, true, 500 );    // 输出:200元定金预购,得到50优惠券
        order( 1, false, 500 );   // 输出:普通购买,无优惠券

Usar o AOP para implementar a cadeia de responsabilidade é simples e engenhoso, mas esse método de empilhamento de funções também sobrepõe o escopo da função.Se a cadeia for muito longa, também terá um impacto maior no desempenho.

Acho que você gosta

Origin blog.csdn.net/weixin_45172119/article/details/128724169
Recomendado
Clasificación