JavaScriptシリーズを深く理解する(38):設計モデルの職責チェーンモデル

5872 ワード

紹介する


職責チェーンモード(Chain of responsibility)は、要求の送信者と受信者との結合関係を回避するために、複数のオブジェクトが要求を処理する機会を与えることである.このオブジェクトをチェーンに接続し、あるオブジェクトが彼を処理するまで、このチェーンに沿ってリクエストを渡します.
すなわち、要求後、最初のオブジェクトから、チェーンで要求を受信したオブジェクトは、それを直接処理するか、チェーン内の次の候補者に転送される.リクエストを送信したオブジェクトは、どのオブジェクトがそれを処理するか、すなわち、リクエストに暗黙的な受信者(implicit receiver)があるかを明確に知らない.実行時刻に応じて、任意の候補者は対応する要求に応答することができ、候補者の数は任意であり、実行時刻にどの候補者がチェーンに参加するかを決定することができます.

本文


JavaScript実装では、そのプロトタイプ特性を利用して職責チェーンモデルを実装できます.
var NO_TOPIC = -1;
var Topic;

function Handler(s, t) {
this.successor = s || null;
this.topic = t || 0;
}

Handler.prototype = {
handle: function () {
if (this.successor) {
this.successor.handle()
}
},
has: function () {
return this.topic != NO_TOPIC;
}
};

Handlerは2つのパラメータを受け入れるだけで、1つ目は後継者(処理要求を伝えるために使用される)、2つ目は伝達レベル(あるレベルで操作を実行するかどうかを制御するために使用されるかどうかを制御するために使用される)、Handlerプロトタイプはhandleメソッドを暴露し、このモードを実装するポイントであり、まず上記のコードの使用方法を見てみましょう.
    var app = new Handler({
handle: function () {
console.log('app handle');
}
}, 3);

var dialog = new Handler(app, 1);

var button = new Handler(dialog, 2);

button.handle();

改変コードはプロトタイプ特性によりbuttonから呼び出される.handle()->dialog.handle()->app.handle()->パラメータ内のhandle()は,最初の3つがプロトタイプを呼び出すhandleであり,最後に受信したパラメータ内のhandleを見つけ,結果を出力する,すなわち実際には最後のレイヤのみが処理する.
では、呼び出し時にdialogのこのオブジェクトだけを処理するにはどうすればいいのでしょうか.dialogインスタンスオブジェクトのhandleメソッドを定義すればいいのですが、new buttonの前に行う必要があります.コードは次のとおりです.
    var app = new Handler({
handle: function () {
console.log('app handle');
}
}, 3);

var dialog = new Handler(app, 1);
dialog.handle = function () {
console.log('dialog before ...')
//
console.log('dialog after ...')
};

var button = new Handler(dialog, 2);

button.handle();

このコードの実行結果は即時dialogである.handleの処理結果は、appに入力されたパラメータで定義されたhandleの実行操作ではありません.
それは自分で処理した後、後継者に処理を続けさせることができますか?答えは肯定的ですが、呼び出されたhandle以降、プロトタイプの特性を利用して次のコードを呼び出す必要があります.
Handler.prototype.handle.call(this);

この文の意味は,プロトタイプのhandleメソッドを呼び出し,その後継者(すなわちsuccessor)のhandleメソッドを呼び出し続けることを意味し,以下のコードはbutton/dialog/appの3つのオブジェクト定義のhandleが実行されると表現される.
var app = new Handler({
handle: function () {
console.log('app handle');
}
}, 3);

var dialog = new Handler(app, 1);
dialog.handle = function () {
console.log('dialog before ...')
//
Handler.prototype.handle.call(this); //
console.log('dialog after ...')
};

var button = new Handler(dialog, 2);
button.handle = function () {
console.log('button before ...')
//
Handler.prototype.handle.call(this);
console.log('button after ...')
};

button.handle();

コードの実行結果から分かるように,まず自分で処理してから後継者の処理を呼び出すには,最後にHandlerを実行する.prototype.handle.call(this);コード、後任者のコードを先に処理したい場合は、先頭でHandlerを実行する.prototype.handle.call(this);コード.

まとめ


ロールチェーンモードは、コンポーネントの親コンポーネントを後継者として使用できるように、コンビネーションモードとともによく使用されます.
同時に、DOMのイベントバブルメカニズムもこれと少し似ているようです.例えば、ボタンをクリックした後、バブルを阻止しなければ、clickイベントは親要素にバブルし続け、このメカニズムを利用して、本シリーズの設計モードの享元モードの「例1:イベント集中管理」のサンプルコードなど、多くの関連問題を処理することができます.
参照コード:https://gist.github.com/1174982

同期と推奨


この文書はディレクトリインデックスに同期されました:JavaScriptシリーズを深く理解する
JavaScriptシリーズの文章を深く理解して、オリジナル、翻訳、転載などの各タイプの文章を含んで、もしあなたに役に立つならば、おじさんに書く動力を推薦して支持してください.