概要責任チェーン パターンは、設計パターンにおける動作設計パターンです。 定義: 複数のオブジェクトにリクエストを処理する機会を与えることで、リクエストの送信者と受信者の間の結合関係を回避し、リクエストを処理するオブジェクトのチェーンを形成し、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 の他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
<<: VPS はオフライン ダウンロード サーバーを構築します (ネットワーク ディスクの時代以降)
nGrinderとは何ですか? nGrinder は、スクリプトの作成、テストの実行、監視、結果レポ...
目次DockerファイルドキュメントJenkins の設定Spring Boot プロジェクトでは、...
ショートハンドプロパティは、複数のプロパティに同時に値を割り当てるために使用されます。たとえば、fo...
多くの場合、ストアド プロシージャを作成するときに配列がよく使用されますが、MySQL ではストアド...
1. 継続的デリバリーとは何かソフトウェア製品の出力プロセスは、ソフトウェアがいつでもリリースできる...
同僚から、LINUX サーバー上の多くのコマンドが (コマンドが見つかりません) というプロンプトで...
目次1. リストインターフェースとその他のモジュールの表示処理2. 従来のインターフェースコンポーネ...
多くの Web ページにはナビゲーション バーに小さな三角形があり、この機能を実装するのは実は非常に...
文章さて、次はレンダリングを見せましょう。画像を見て初めて理解することに興味が湧くでしょう。そうでな...
1. ファイル削除コマンド:対応するディレクトリを検索します -mtime + 日数 -name &...
ほとんどのナビゲーション バーは、下の図に示すように水平に配置されていますが、これはどのように実現さ...
rpmインストールパッケージを使用してmysqlをオフラインでインストールします。参考までに準備:公...
データ共有プロトタイプにはどのようなデータを書き込む必要がありますか?共有する必要があるデータはプロ...
今日から、定期的にちょっとした豆知識を整理していきます。簡単なものもあるかもしれませんが、どれも役に...
1. WEBでサポートされている画像形式: GIF: 256色を保存でき、透明色をサポートし、アニメ...