JavaScript デザインパターン 責任連鎖パターン

JavaScript デザインパターン 責任連鎖パターン

概要

責任チェーン パターンは、設計パターンにおける動作設計パターンです。

定義: 複数のオブジェクトにリクエストを処理する機会を与えることで、リクエストの送信者と受信者の間の結合関係を回避し、リクエストを処理するオブジェクトのチェーンを形成し、1 つのオブジェクトがリクエストを処理するまでチェーンに沿ってリクエストを渡します。

平易な言葉で説明すると、筆者は人口1000万人を超える新一線都市である武漢にいます。朝のラッシュアワーのバスを例にとると、朝のラッシュアワーにはバスの前ドアは通常混雑しているため、カードをスワイプしてバスに乗ることはできませんが、後ドアは比較的空いています。このとき、後ドアからバスに乗ることを選択しますが、後ドアからバスに乗るとカードをスワイプできません。請求書から逃げているのでしょうか?いいえ、これは、新世代の文明的でよく教育された若者である私たちがすべきことではありません。そこで、バスカードを前に渡し、前の乗客にカードリーダーに渡してカードをスワイプするのを手伝ってもらいます。しかし、私たちは後部ドアにいて、カードリーダーは前部ドアにあります。カードを渡す過程で、複数の乗客にバスカードを渡すのを手伝ってもらいます。このパスのプロセスは責任チェーンモデルであり、カードを渡す各乗客は責任チェーンのノードオブジェクトです。

コードの実装

携帯電話を販売する電子商取引サイトがあるとします。500元の保証金と200元の定価で2回の予約(この時点で注文が生成されます)を経て、正式な購入の段階に達しました。当社では、前金をお支払いいただいたお客様に対して、一定の優遇措置を設けております。正式に購入する場合、500元の保証金を支払った顧客には100元のモールクーポンが、200元を支払った顧客には50元のモールクーポンが提供されます。以前に保証金を支払ったことがない顧客にはクーポンは提供されず、在庫が限られている場合は購入できない場合があります。

パラメータ定義

1.orderType: 注文タイプ (入金ユーザーまたは一般ユーザー) を示します。コード値が 1 の場合、ユーザーの入金額は 500 元、2 の場合、ユーザーの入金額は 200 元、3 の場合、ユーザーの入金額は 300 元であることを意味します。

2.pay: ユーザーがデポジットを支払ったかどうかを示します。値は true または false です。ユーザーは500元の保証金を支払って注文したが、保証金を支払っていない場合は、一般ユーザーとしてのみ購入することができます。

3. 在庫:一般ユーザーが携帯電話を購入するための在庫数を示します。500元または200元の保証金を支払った顧客にはこの制限は適用されません。

成し遂げる

var order = function(orderType, pay, stock){
    if ( orderType === 1 ){ // 500 元のデポジット購入モードif ( pay === true ){ // デポジット paidconsole.log( '500 元のデポジットで予約注文、クーポン 100 枚ゲット' );
        }else{ // デポジットが支払われていないため、通常の購入モードにダウングレードしますif ( stock > 0 ){ // 通常購入用の携帯電話はまだ在庫にありますconsole.log( '通常購入、クーポンなし' );

            }それ以外{
                console.log('携帯電話の在庫が不足しています');
            }
        }
    }
    else if ( orderType === 2 ){ // 200元のデポジット購入モードif ( pay === true ){
            console.log('200元のデポジットで予約注文すると、50元のクーポンがもらえます');
        }それ以外{
            (在庫>0)の場合
                console.log('通常購入、クーポンなし');
            }それ以外{
                console.log('携帯電話の在庫が不足しています');
            }
        }
    }
    そうでない場合 ( orderType === 3 ) {
        (在庫>0)の場合
            console.log('通常購入、クーポンなし');
        }それ以外{
            console.log('携帯電話の在庫が不足しています');
        }
    }
};
order( 1 , true, 500); // 予約注文の場合は500元のデポジット、100元のクーポンをゲット

上記のコードは確かに必要な機能を実現できますが、上記のコードの構造は明らかに不明瞭であり、順序関数メソッドは巨大で、結合度が高くなっています。

責任連鎖パターンの実装

上記の機能を実装するために、責任チェーンパターンを使用します。まず、500 元預金注文、200 元預金注文、および通常注文を 3 つの機能に分割し、orderType、pay、stock の 3 つのパラメーターを渡します。500 元注文機能が処理条件を満たさない場合、リクエストは 200 元注文機能に渡されます。200 元注文機能も処理条件を満たさない場合、リクエストは通常​​注文機能に渡されます。

var order500 = function( orderType, pay, stock ) {
    if ( orderType === 1 && pay === true ){
        console.log('500元のデポジットで予約注文すると、100元のクーポンがもらえます');
    }それ以外{
        order200( orderType, pay, stock ); // リクエストを200元の注文に渡す }
};
// 200 元の注文 var order200 = function( orderType, pay, stock ){
    if ( orderType === 2 && pay === true ){
        console.log('200元のデポジットで予約注文すると、50元のクーポンがもらえます');
    }それ以外{
        orderNormal( orderType, pay, stock ); // リクエストを通常の注文に渡す }
};
// 通常の購入注文 var orderNormal = function( orderType, pay, stock ){
    (在庫>0)の場合
        console.log('通常購入、クーポンなし');
    }それ以外{
        console.log('携帯電話の在庫が不足しています');
    }
};

// テスト結果:
order500( 1 , true, 500 ); // 予約注文で500元のデポジット、100元のクーポンをゲットorder500( 1, false, 500 ); // 通常購入、クーポンなしorder500( 2, true, 500 ); // 予約注文で200元のデポジット、500元のクーポンをゲットorder500( 3, false, 500 ); // 通常購入、クーポンなしorder500( 3, false, 0 ); // 在庫切れ

変更されたコードの構造は以前よりもはるかに明確になり、関数が分割され、多くの if-else 分岐判断が削除されていることがわかります。

たとえそうであったとしても、変更されたコードは依然としてオープン/クローズ原則に違反しています。なぜなら、後で要件が変わった場合、これらの関数の内部を変更する必要があるからです。これは明らかに私たちが望んでいることではありません。

改善

まず、関数が処理条件を満たさない場合は nextSuccessor を返し、処理条件を満たす場合は実行されることに同意します。

var order500 = function( orderType, pay, stock ) {
    if ( orderType === 1 && pay === true ){
        console.log('500 元のデポジットで予約注文すると 100 元のクーポンがもらえます');
    }それ以外{
        return 'nextSuccessor'; // 次のノードが誰かわからないので、とにかくリクエストを後ろに渡します}
};

var order200 = function( orderType, pay, stock ) {
    if ( orderType === 2 && pay === true ){
        console.log('200 元のデポジットで予約注文すると 50 元のクーポンがもらえます');
    }それ以外{
        return 'nextSuccessor'; // 次のノードが誰かわからないので、とにかくリクエストを後ろに渡します}
};

var orderNormal = function( orderType, pay, stock ) {
    (在庫>0)の場合
        console.log('通常購入、クーポンなし');
    }それ以外{
        console.log('携帯電話の在庫が不足しています');
    }
};

var チェーン = 関数(fn){
    this.fn = fn;
    this.successor = null;
};

//リクエストを次のノードに渡す Chain.prototype.setNextSuccessor = function( successor ){
    this.successor = successor を返します。
};

//リクエストをノードに渡す Chain.prototype.passRequest = function(){

   //インスタンスを受け取ってパラメータを配列として保存した後のメソッド var ret = this.fn.apply( this, arguments );
    コンソールにログ出力します。

    //ret は nextSuccessor と等しいため、処理条件が満たされず、実行を継続する必要があることを意味します if (ret === 'nextSuccessor') {

     //これは論理短絡戻りであり、ユニオンの 1 つが false の場合は false です。this.successor が存在する場合は、後続の実行結果が返されます。this.successor が存在しない場合は、未定義の this.nextSuccessor の値が返されます。
        this.successor と this.successor.passRequest.apply( this.successor, arguments ) を返します。
    }
};


var chainOrder500 = 新しいチェーン( order500 );
var chainOrder200 = 新しいチェーン( order200 );
var chainOrderNormal = 新しい Chain( orderNormal );    

//責任ノードのチェーンを渡します chainOrder500.setNextSuccessor( chainOrder200 );
チェーンオーダー200.setNextSuccessor(チェーンオーダー通常);

chainOrder500.passRequest( 1, true, 500 ); // 予約注文で500元のデポジット、クーポン100枚をゲット chainOrder500.passRequest( 2, true, 500 ); // 予約注文で200元のデポジット、クーポン50枚をゲット chainOrder500.passRequest( 3, true, 500 ); // 通常購入、クーポンなし chainOrder500.passRequest( 1, false, 0 ); // 在庫切れ

改良後は需要が変化して300の保証金が必要な注文になっても簡単に対応できるようになりました。

var order300 =関数(){
  //特定の実装動作};

チェーンオーダー300 =新しいチェーン(オーダー300);
チェーンオーダー500.setNextSuccessor(チェーンオーダー300);
チェーンオーダー300.setNextSuccessor(チェーンオーダー200);

ヒント:

補足知識:論理短絡。JS の基礎知識ですが、忘れてしまうのは避けられません。この記事を書いたときに忘れていました。

結合の 1 つが false の場合、結果は false になります。結合 (AND) 関係の場合、最初の数値は false または存在しないため、2 番目の数値の値が直接返されます。

var x = a && b && c は var x = a; と同等です。
もし(a){
    x = b;
    もし(b){
       x = c;
    }
}

2 つのうち 1 つが true の場合、true になります。or-set (or) 関係の場合、最初の数値が true であれば最初の数値が直接返され、最初の数値が false であれば 2 番目の数値が直接返されます。

var x = a || b || c は次の式と同等です:

var x;
もし(a){
    x = a;
} そうでなければ(b){
    x = b;
} それ以外 {
    x = c;
}

上記の太字の 2 つの文を覚えておけば、基本的には論理的な短絡を巧みに使用できます。

上記は、JavaScript デザインパターンの責任チェーンパターンの詳細です。JavaScript デザインパターンの詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • JavaScript デザインパターンの学習 アダプタパターン
  • JavaScript デザインパターン プロキシパターンの学習
  • JavaScript デザインパターン コマンドパターン
  • js の一般的なデザインパターンの詳細な説明
  • JavaScript デザインパターン戦略パターン実装原則詳細説明
  • JavaScript 組み合わせデザインパターン - 改善導入事例分析
  • JavaScript デザインパターン - ブリッジパターン操作例の導入の分析
  • JavaScript デザイン パターン - シンプルなファクトリ パターンの例の分析 [XHR ファクトリ ケース]
  • JavaScript デザイン パターン - シンプルなファクトリー パターンの詳細な定義と適用例
  • JAVA のデザインパターンの 6 つの原則

<<:  VPS はオフライン ダウンロード サーバーを構築します (ネットワーク ディスクの時代以降)

>>:  MySQLの使用中に発生した問題

推薦する

基本構造、ドキュメント タイプ、ヘッダー、本文などの一般的な HTML 要素の概要。

1. 基本構造:コードをコピーコードは次のとおりです。 <!DOCTYPE html PUBL...

Node.jsを使用してホットリロードページを実装する方法の詳細な説明

序文少し前に、browser-sync+gulp+gulp-nodemon を組み合わせて、本番環境...

CSS グリッドレイアウトで列にアイテムを埋め込む方法

n 個のアイテムがあり、これらのアイテムをグリッド レイアウトの列に並べ替える必要があるとします。列...

Linux 上で Python3.6 をコンパイルしてインストールするための詳細なチュートリアル

1. まず、公式ウェブサイト https://www.python.org/downloads/so...

Docker インストール Nginx チュートリアル 実装図

Nginx をインストールして試してみましょう。画像はクラスであり、コンテナはオブジェクトであること...

MySQLデータベースを別のマシンに移行する方法の詳細な説明

1. まず、移行サーバー上のデータ ファイルを見つけます。MySQL 5.7 とデフォルトのインスト...

波効果を作成するための CSS のトリック

純粋な CSS を使用して波の効果を実現することは、常に非常に困難でした。 波形曲線を実現するにはベ...

Win10 システムに MySQL8.0.13 をインストールする際の問題と解決策

オペレーティングシステム: Windows10 MySQL バージョン: 8.0.13-winx64...

いくつかの面接の質問を使ってJavaScriptの実行メカニズムを調べる

目次前の単語同期と非同期前菜プレートを追加マクロタスク マイクロタスク約束しましょうタイマーを追加す...

IE における条件付きコメントの利点と欠点

IE の条件付きコメントは、通常の (X)HTML コメントに対する Microsoft 独自の (...

JavaScriptの信頼性の低い未定義

undefined JavaScript では、値が undefined かどうかを判断したい場合は...

HTML のテキストエリアの改行問題の概要

最近、Textrea に転送したときに、データが本当に行ごとに保存できるかどうかという問題に遭遇しま...

Zabbixを使用してMySQLを監視する方法

Zabbix 導入ドキュメントzabbix導入後zabbixエージェントの操作1. MySQLを監視...

MySQL のスロークエリの方法と例

1. はじめにスロークエリログを有効にすると、MySQL は指定された時間を超えるクエリステートメン...

Nginx リバース プロキシを使い始める

目次概要リバースプロキシの役割Nginx リバース プロキシ イントラネット侵入 8081 ポートの...