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の使用中に発生した問題

推薦する

Docker を使用した nGrinder パフォーマンス テスト プラットフォームの導入プロセスの分析

nGrinderとは何ですか? nGrinder は、スクリプトの作成、テストの実行、監視、結果レポ...

Jenkins は Docker イメージを構築し、Harbor ウェアハウスにプッシュします

目次DockerファイルドキュメントJenkins の設定Spring Boot プロジェクトでは、...

CSS でショートカット プロパティを記述する際は、トラブルの順序に注意してください (落とし穴を避けるため)

ショートハンドプロパティは、複数のプロパティに同時に値を割り当てるために使用されます。たとえば、fo...

MySQL に配列を保存するサンプルコードと方法

多くの場合、ストアド プロシージャを作成するときに配列がよく使用されますが、MySQL ではストアド...

Docker での Jenkins と Docker を使用した継続的デリバリー

1. 継続的デリバリーとは何かソフトウェア製品の出力プロセスは、ソフトウェアがいつでもリリースできる...

元のPATHを上書きしてコマンドが見つからないというメッセージが表示されるコマンド失敗の問題を解決する方法

同僚から、LINUX サーバー上の多くのコマンドが (コマンドが見つかりません) というプロンプトで...

Vue Element フロントエンドアプリケーション開発 従来の Element インターフェースコンポーネント

目次1. リストインターフェースとその他のモジュールの表示処理2. 従来のインターフェースコンポーネ...

小さな三角形の実装コードを含む CSS ナビゲーション バー メニュー

多くの Web ページにはナビゲーション バーに小さな三角形があり、この機能を実装するのは実は非常に...

CSS3 を使用してピカチュウのアニメーション壁紙を作成する例

文章さて、次はレンダリングを見せましょう。画像を見て初めて理解することに興味が湧くでしょう。そうでな...

Linux は n 日前のログとサンプルコマンドを自動的に削除します

1. ファイル削除コマンド:対応するディレクトリを検索します -mtime + 日数 -name &...

HTML における li タグの水平配置の例

ほとんどのナビゲーション バーは、下の図に示すように水平に配置されていますが、これはどのように実現さ...

CentOS 6.4 で rpm を使用して MySQL をオフラインでインストールする

rpmインストールパッケージを使用してmysqlをオフラインでインストールします。参考までに準備:公...

JavaScript プロトタイプのデータ共有とメソッド共有の実装を調べる

データ共有プロトタイプにはどのようなデータを書き込む必要がありますか?共有する必要があるデータはプロ...

ページ要素の絶対位置と相対位置に関するある程度の理解

今日から、定期的にちょっとした豆知識を整理していきます。簡単なものもあるかもしれませんが、どれも役に...

HTML ページに画像を挿入し、マップ インデックスを追加する方法の例

1. WEBでサポートされている画像形式: GIF: 256色を保存でき、透明色をサポートし、アニメ...