[解決済み] なぜPublish/Subscribeパターンを(JS/jQueryで)使用するのか?
質問
同僚が(JS/jQueryの)公開/購読パターンを紹介してくれたのですが、私はこのパターンを理解するのに苦労しています。 なぜ を理解するのに苦労しています。
例えば、以前は以下のようなコードでした。
$container.on('click', '.remove_order', function(event) {
event.preventDefault();
var orders = $(this).parents('form:first').find('div.order');
if (orders.length > 2) {
orders.last().remove();
}
});
そして、代わりにこうすることのメリットもわかりました、例えば...。
removeOrder = function(orders) {
if (orders.length > 2) {
orders.last().remove();
}
}
$container.on('click', '.remove_order', function(event) {
event.preventDefault();
removeOrder($(this).parents('form:first').find('div.order'));
});
を再利用する機能を導入しているためです。
removeOrder
機能を再利用できるようになるからです。
しかし、同じことをするのであれば、なぜパブリッシュ/サブスクライブパターンを実装しようと思い、以下のような長さにしたのでしょうか?(参考までに、私は jQuery tiny pub/sub )
removeOrder = function(e, orders) {
if (orders.length > 2) {
orders.last().remove();
}
}
$.subscribe('iquery/action/remove-order', removeOrder);
$container.on('click', '.remove_order', function(event) {
event.preventDefault();
$.publish('iquery/action/remove-order', $(this).parents('form:first').find('div.order'));
});
このパターンについて確かに読みましたが、なぜこれが必要になるのか想像がつきません。私が見たチュートリアルの説明では どのように を説明しているチュートリアルを見たことがありますが、私が作成したものと同じような基本的な例しかカバーしていません。
pub/subの有用性は、より複雑なアプリケーションで明らかになると想像していますが、想像がつきません。私は完全にポイントを逃していると思いますが、もしポイントがあれば知りたいです!
次のような説明をお願いします。 簡潔に なぜ、そしてどのような状況でこのパターンが有利なのか?上記の私の例のようなコードスニペットに pub/sub パターンを使用する価値はありますか?
どのように解決するのですか?
それは、緩やかな結合と単一の責任であり、ここ数年非常にモダンなJavaScriptのMV*(MVC/MVP/MVVM)パターンに密接に関連しています。
疎結合 はオブジェクト指向の原則で、システムの各コンポーネントが自分の責任を自覚し、他のコンポーネントを気にしない(少なくとも可能な限り気にしないようにする)ことを指します。疎結合は、異なるモジュールを簡単に再利用できるため、良いことです。他のモジュールのインターフェースと結合することはない。publish/subscribeを使う場合、publish/subscribeインターフェースとしか結合していないことになりますが、これは大きな問題ではありません。ですから、もしあなたが別のプロジェクトでモジュールを再利用しようと決めたら、それをコピー&ペーストするだけで、おそらく動作するでしょうし、少なくとも動作させるためにそれほど努力する必要はないでしょう。
ルースカップリングについて話すとき、私たちは 懸念の分離 . MV*アーキテクチャパターンを使ってアプリケーションを構築する場合、常にモデル(複数可)とビュー(複数可)が存在します。モデルはアプリケーションのビジネス部分です。このモデルは、異なるアプリケーションで再利用することができます。そのため、1つのアプリケーションのビューと組み合わせて表示することは良いアイデアではありません。そのため、モデル-ビュー間の通信にパブリッシュ/サブスクライブを使用するのは良い考えです。モデルが変更されると、イベントが発行され、ビューはそれをキャッチして自分自身を更新します。パブリッシュ/サブスクライブによるオーバーヘッドはなく、デカップリングのために役立ちます。同じように、例えばアプリケーションのロジックをコントローラ(MVVM、MVPは正確にはコントローラではありません)に保持し、Viewをできるだけシンプルに保つことができます。View が変更されたとき (あるいはユーザが何かをクリックしたときなど) は、単に新しいイベントを発行し、Controller がそれを捕捉して何をすべきかを決定します。もしあなたが MVC パターンに詳しい方、あるいは MVVM のようなパブリッシュ/サブスクライブを考えることができます。 Observerパターン . このアプローチは、Backbone.jsやKnockout.js(MVVM)などのフレームワークで使用されています。
以下はその例です。
//Model
function Book(name, isbn) {
this.name = name;
this.isbn = isbn;
}
function BookCollection(books) {
this.books = books;
}
BookCollection.prototype.addBook = function (book) {
this.books.push(book);
$.publish('book-added', book);
return book;
}
BookCollection.prototype.removeBook = function (book) {
var removed;
if (typeof book === 'number') {
removed = this.books.splice(book, 1);
}
for (var i = 0; i < this.books.length; i += 1) {
if (this.books[i] === book) {
removed = this.books.splice(i, 1);
}
}
$.publish('book-removed', removed);
return removed;
}
//View
var BookListView = (function () {
function removeBook(book) {
$('#' + book.isbn).remove();
}
function addBook(book) {
$('#bookList').append('<div id="' + book.isbn + '">' + book.name + '</div>');
}
return {
init: function () {
$.subscribe('book-removed', removeBook);
$.subscribe('book-aded', addBook);
}
}
}());
もうひとつの例です。もしMV*のアプローチが好きでないなら、少し違うものを使うことができます(次に説明するものと最後に述べたものとの間に交差点があるのです)。アプリケーションを異なるモジュールで構成すればいいのです。例えば、Twitterを見てください。
インターフェイスを見ると、単純にいろいろな箱がありますね。それぞれのボックスは、異なるモジュールと考えることができます。たとえば、ツイートを投稿することができます。このアクションでは、いくつかのモジュールの更新が必要です。まず、プロフィールデータ(左上のボックス)を更新しなければなりませんが、タイムラインも更新しなければなりません。もちろん、両方のモジュールへの参照を保持し、それぞれのパブリック・インターフェースを使用して別々に更新することもできますが、イベントを公開するだけの方が簡単です(そして、より良いです)。そうすることで、カップリングが緩やかになり、アプリケーションの修正が容易になります。もし、新しいツイートに依存する新しいモジュールを開発したら、"publish-tweet" イベントを購読して、それを処理すればいいだけです。このアプローチは非常に便利で、アプリケーションを非常に非連続にすることができます。モジュールを簡単に再利用することができます。
最後のアプローチの基本的な例です(これはオリジナルのtwitterのコードではなく、単なる私のサンプルです)。
var Twitter.Timeline = (function () {
var tweets = [];
function publishTweet(tweet) {
tweets.push(tweet);
//publishing the tweet
};
return {
init: function () {
$.subscribe('tweet-posted', function (data) {
publishTweet(data);
});
}
};
}());
var Twitter.TweetPoster = (function () {
return {
init: function () {
$('#postTweet').bind('click', function () {
var tweet = $('#tweetInput').val();
$.publish('tweet-posted', tweet);
});
}
};
}());
このアプローチについては、以下のような素晴らしい講演があります。 ニコラス・ザカス . MV*のアプローチについては、私が知る限り最も優れた論文や書籍が、以下の出版社から出版されています。 アディ・オスマニ .
欠点は publish/subscribeの使いすぎに注意する必要があります。何百ものイベントがある場合、それらをすべて管理するのは非常に困難になります。また、名前空間を使っていない(または正しい方法で使っていない)場合、衝突が発生する可能性があります。パブリッシュ/サブスクライブによく似たMediatorの高度な実装は、こちらにあります。 https://github.com/ajacksified/Mediator.js . 名前空間やイベントの「バブリング」のような機能があり、もちろん中断することも可能です。パブリッシュ/サブスクライブのもう一つの欠点は、ユニットテストが難しいことです。モジュール内の異なる機能を分離し、それらを独立してテストすることが難しくなる可能性があります。
関連
-
[解決済み] jQueryを使って要素のIDを取得するにはどうすればよいですか?
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] 私のJavaScriptコードは "No 'Access-Control-Allow-Origin' header is present on requested resource "というエラーを受け取りますが、Postmanはそうならないのはなぜですか?
-
[解決済み] なぜ ++[[]][+[] +[+[]] は "10" という文字列を返すのでしょうか?
-
[解決済み] jQueryでJavaScriptオブジェクトから選択する際に、オプションを追加する最も良い方法は何ですか?
-
[解決済み] jQueryを使用してハイパーリンクのhref属性を変更する方法
-
[解決済み] Reactコンポーネント外でのクリックを検出する
-
[解決済み] オブザーバー、Pub/Sub、データバインディングの違いについて
-
[解決済み] JavaScriptで次の要素/前の要素を取得しますか?
-
[解決済み] 上級者向けJavaScript。この関数はなぜ括弧でくくられるのですか?重複
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 配列からオブジェクトを生成する
-
[解決済み] <Enter>でjQuery UIダイアログを送信する
-
[解決済み] jqueryでdivの要素がオーバーフローしていないかチェックする
-
[解決済み] JavaScriptのtoString()関数をオーバーライドして、デバッグ用に意味のある出力を提供することは可能でしょうか?
-
[解決済み] コールバック地獄とは何か、RXはそれをどのように、そしてなぜ解決するのか?
-
[解決済み] Chromeの拡張機能開発にWebStormを使用するにはどうすればよいですか?
-
[解決済み] jQueryを使用して、すべてのクリックイベントハンドラを削除するにはどうすればよいですか?
-
[解決済み] V8 Javascript エンジンのスタンドアロン実行
-
[解決済み] Chrome拡張機能:popup.htmlを強制終了させる
-
[解決済み] 変異を伴わないオブジェクトからの値の削除