はじめに
オブザーバー モードは、パブリッシュ/サブスクライブ モード (パブリッシュ/サブスクライブ) とも呼ばれ、1 対多の関係を定義し、複数のオブザーバー オブジェクトが特定のトピック オブジェクトのステータスを同時に監視できるようにします。トピック オブジェクトが変更されると、すべてのオブザーバー オブジェクトが通知され、オブジェクト自体が自動的に更新されます。
オブザーバー パターンを使用する利点:
1. 単純なブロードキャスト通信をサポートし、サブスクライブされたすべてのオブジェクトに自動的に通知します。
2. ページがロードされた後、ターゲット オブジェクトはオブザーバーと動的な関係を簡単に持つことができるため、柔軟性が向上します。
3. ターゲットオブジェクトとオブザーバーの間の抽象的な結合関係は、独立して拡張および再利用できます。
テキスト (バージョン 1)
JS でのオブザーバー パターンの実装は、コールバックを通じて実現されます。まず、subscribe、unsubscribe、publish の 3 つのメソッドを含む pubsub オブジェクトを定義します。
var pubsub = {};
(関数 (q) {
var topic = {}, // コールバック関数に格納される配列
subUid = -1;
//メソッドを公開
q.publish = 関数 (トピック, 引数) {
if (!topics[トピック]) {
return false;
}
setTimeout(function() {
varsubscribers = トピック[トピック],
len = 購読者.length : 0;
しながら (len--) {
subscribers[len].func(topic, args);
}
}, 0);
true を返します;
};
//サブスクリプションメソッド
q.subscribe = function (topic, func) {
if (!topics[トピック]) {
トピック[トピック] = [];
}
var token = ( subUid).toString();
トピック[トピック].push({
トークン: トークン、
func: func
});
トークンを返す;
};
//購読を解除する方法
q.unsubscribe = 関数 (トークン) {
for (トピック内の変数 m) {
if (トピック[m]) {
for (var i = 0, j = topic[m].length; i
If (トピックス[m][i].token === トークン) {
トピック[m].splice(i, 1);
トークンを返す;
}
}
}
}
return false;
};
} (pubsub));
次のように使用します:
// ぜひ購読してください
pubsub.subscribe('example1', 関数 (トピック, データ) {
console.log(トピック ": " データ);
});
//通知を公開
pubsub.publish('example1', 'hello world!');
pubsub.publish('example1', ['test', 'a', 'b', 'c']);
pubsub.publish('example1', [{ 'color': 'blue' }, { 'text': 'hello'}]);
どうですか?すごく使いやすいんじゃないでしょうか?しかし、この方法には問題があります。つまり、購読を解除する方法がないということです。購読を解除したい場合は、購読解除の名前を指定する必要があるため、別のバージョンを考えてみましょう:
//サブスクライブを解除する変数にサブスクリプションを割り当てます
var testSubscription = pubsub.subscribe('example1', function (トピック, データ) {
console.log(トピック ": " データ);
});
//通知を公開
pubsub.publish('example1', 'hello world!');
pubsub.publish('example1', ['test', 'a', 'b', 'c']);
pubsub.publish('example1', [{ 'color': 'blue' }, { 'text': 'hello'}]);
//購読を解除
setTimeout(function() {
pubsub.unsubscribe(testSubscription);
}, 0);
//再度パブリッシュして、情報がまだ出力できるかどうかを確認します
pubsub.publish('example1', 'こんにちは! (これは失敗します)');
バージョン 2
プロトタイプの特性を使用してオブザーバー パターンを実装することもできます。コードは次のとおりです。
function Observer() {
This.fns = [];
}
Observer.prototype = {
購読: function (fn) {
This.fns.push(fn);
}、
購読解除: function (fn) {
this.fns = this.fns.filter(
関数 (el) {
If (el !== fn) {
}
}
);
}、
更新: function (o, thisObj) {
varscope = thisObj || window;
This.fns.forEach(
関数 (el) {
el.call(scope, o);
}
);
}
};
//テスト
var o = 新しいオブザーバー;
var f1 = 関数 (データ) {
console.log('ロビン: ' データ '、すぐに作業を始めてください!');
};
var f2 = 関数 (データ) {
console.log('ランドール: ' データ '、給料を増やすように頼んでください!');
};
o.subscribe(f1);
o.subscribe(f2);
o.update("トムが帰ってきた!")
// f1 の購読を解除
o.unsubscribe(f1);
// 再度検証します
o.update("トムが帰ってきた!");
フィルターまたは forEach 関数が見つからないというメッセージが表示された場合は、ブラウザーが新しくなく、現在新しい標準関数をサポートしていない可能性があります。次の方法を使用して自分で定義できます。
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (fn, thisObj) {
varscope = thisObj || window;
for (var i = 0, j = this.length; i
fn.call(scope, this[i], i, this);
}
};
}
if (!Array.prototype.filter) {
Array.prototype.filter = function (fn, thisObj) {
varscope = thisObj || window;
var a = [];
for (var i = 0, j = this.length; i
If (!fn.call(scope, this[i], i, this)) {
続行;
}
a.push(this[i]);
}
return a;
};
}
バージョン 3
複数のオブジェクトにオブザーバーのパブリッシュおよびサブスクライブ関数を持たせたい場合は、一般的な関数を定義し、この関数の関数をオブザーバー関数が必要なオブジェクトに適用できます。コードは次のとおりです。
//一般的なコード
var オブザーバー = {
//購読
AddSubscriber: 関数 (コールバック) {
This.subscribers[this.subscribers.length] = コールバック;
}、
//購読を解除
removeSubscriber: 関数 (コールバック) {
for (var i = 0; i
If (this.subscribers[i] === コールバック) {
delete (this.subscribers[i]);
}
}
}、
//公開
パブリッシュ: 関数 (何を) {
for (var i = 0; i
If (typeof this.subscribers[i] === '関数') {
This.subscribers[i](何を);
}
}
}、
// オブジェクトにオブザーバー関数を持たせる
Make: function (o) {
for (var i in this) {
o[i] = this[i];
o.subscribers = [];
}
}
};
次に、blogger と user の 2 つのオブジェクトをサブスクライブし、observer.make メソッドを使用して、これら 2 つのオブジェクトにオブザーバー関数を持たせます。コードは次のとおりです。
コードをコピー コードは次のとおりです:
var blogger = {
推奨: function (id) {
var msg = 'dudu が推奨する投稿:' id;
This.publish(msg);
}
};
var user = {
投票: 関数 (id) {
var msg = '誰かが投票しました! ID=' id;
This.publish(msg);
}
};
オブザーバー.make(ブロガー);
オブザーバー.make(ユーザー);
使用方法は比較的簡単です。さまざまなコールバック関数をサブスクライブして、さまざまなオブザーバー オブジェクトに登録できます (同時に複数のオブザーバー オブジェクトに登録することもできます)。
var tom = {
読み取り: 関数 (何を) {
console.log('トムは次のメッセージを見ました: ' 何)
}
};
var mm = {
show: 関数 (何を) {
console.log('mm は次の情報を確認しました: ' 何を)
}
};
// 購読
blogger.addSubscriber(tom.read);
blogger.addSubscriber(mm.show);
blogger.recommend(123); //公開するために呼び出します
//購読を解除
blogger.removeSubscriber(mm.show);
blogger.recommend(456); //公開するために呼び出します
//別のオブジェクトのサブスクリプション
user.addSubscriber(mm.show);
user.vote(789); //公開を呼び出します
jQuery バージョン
jQuery バージョン 1.7 の新しいオン/オフ関数に従って、jQuery バージョンのオブザーバーを定義することもできます。
(関数 ($) {
var o = $({});
$.subscribe = function () {
o.on.apply(o, 引数);
};
$.unsubscribe = function () {
o.off.apply(o, 引数);
};
$.publish = function () {
o.trigger.apply(o, 引数);
};
} (jQuery));
呼び出しメソッドは、上記の 3 つのバージョンよりも単純です:
//コールバック関数
関数ハンドル(e, a, b, c) {
// `e` はイベントオブジェクトなので注意する必要はありません
console.log(a b c);
};
//購読
$.subscribe("/some/topic", ハンドル);
//公開
$.publish("/some/topic", ["a", "b", "c"]) // 出力 abc
$.unsubscribe("/some/topic", handle) // 購読解除
;
//購読
$.subscribe("/some/topic", function (e, a, b, c) {
console.log(a b c);
});
$.publish("/some/topic", ["a", "b", "c"]) // 出力 abc
//Unsubscribe (unsubscribe ではコールバック関数の代わりに /some/topic 名が使用されます。これはバージョン 1 の例とは異なります
$.unsubscribe("/some/topic");
ご覧のとおり、彼のサブスクリプションとサブスクリプション解除ではコールバック関数名の代わりに文字列名が使用されているため、匿名関数が渡された場合でもサブスクリプションを解除できます。
概要
オブザーバーの使用例は次のとおりです。1 つのオブジェクトを変更するときに他のオブジェクトも同時に変更する必要があり、変更する必要があるオブジェクトの数が不明な場合は、オブザーバー パターンの使用を検討する必要があります。
一般に、オブザーバー パターンが行うことは分離であり、結合の両当事者が具体性ではなく抽象化に依存するようになります。そのため、それぞれの側での変更がもう一方の側の変更に影響を与えません。