這個模式用來做爲中間人,一個把發佈者和訂閱者架接在一塊兒的代理。發佈者是當完成某些過程的時候觸發事件的對象,訂閱者是但願當發佈者發佈的時候但願被通知的對象。app
生活中有一個很好地例子,廣播電臺,人們會把頻道調到他們最喜歡的節目。廣播站不知道觀衆聽得是什麼或者他們正在聽什麼。他只須要發佈他們的節目就能夠啦。觀衆也不知道廣播站製做節目的過程。他們只要在他們最喜歡的節目運行的時候把臺調到對應的頻道或者告知朋友就行。測試
發佈/訂閱者模式實現了鬆耦合:你可讓發佈者發佈消息,訂閱者接受消息而不是尋找一種方式把兩個分離的系統鏈接在一塊兒。this
鬆耦合prototype
發佈者不須要知道訂閱者的數量,訂閱者聽得話題或者訂閱者是經過什麼方式運行的。他們可以相互獨立地運行,這樣就可讓你分開開發這兩部分而不須要擔憂對狀態或實現的任何細微的影響。設計
可擴展性代理
發佈/訂閱模式可讓系統在不管何時沒法負載的時候擴展rest
更乾淨地設計code
充分地利用好發佈/訂閱模式,你不得不深刻地思考不一樣的組件是如何交互的。這一般會讓咱們有更乾淨地設計由於咱們對解耦和鬆耦合的強調。對象
靈活性
你不須要擔憂不一樣的組件是如何組合在一塊兒的。只要他們共同遵照一份協議
容易測試
你能夠很好地找出發佈者或訂閱者是否會獲得錯誤的信息
發佈/訂閱模式最大的有點是解耦,但同時也是最大的缺點:
中間人也許不會通知系統消息傳送的狀態。因此咱們沒法知道消息傳送是成功的仍是失敗的。緊耦合是須要保證這一點的。
發佈者不知道訂閱者的狀態,反之亦然,這樣的話,你根本不知道在另外一端是否會沒有問題?
隨着訂閱者和發佈者數量的增長,不斷增長的消息傳送回致使架構的不穩定,容易在負載大的時候出問題
攻擊者(惡意的發佈者)可以入侵系統而且撕開它。這會致使惡意的消息被髮布,訂閱者可以得到他們之前並不能得到的消息。
更新發布者和訂閱者的關係會是一個很難的問題,由於畢竟他們根本不認識對方。
須要中間人/代理商,消息規範和相關的規則會給系統增長一些複雜度
現實沒有銀彈,可是這個模式是設計鬆耦合系統的很好地方式。這和RSS,Atom和PubSubHubbub的思想同樣。
發佈/訂閱模式例子(Javascript)
var makePubSub=function(){ var callbacks={}, publish=function(){ //Turn arguments object into real array var args=Array.prototype.slice.call(arguments,0); //Extract the event name which is the first entry var ev=args.shift(); //Return if callbacks object doesn't contain //any entry for event var list,i,l; if(!callbacks[ev]){ return this; } list=callbacks[ev]; //Invoke the callbacks,passing in the rest of parameters for(i=0,l=list.length;i<l;i++){ list[i].apply(this,args); } return this; }, subscribe=function(ev,callback){ //Check if ev is already registered //If it isn't create an array entry for it if(!callbacks[ev]){ callbacks[ev]=[]; } callbacks[ev].push(callback); return this; }; return {pub:publish,sub:subscribe}; } test=makePubSub(); test.sub("alert",function(){alert("hell0");}) test.pub("alert");