『设计模式』80年代的人们就已经领悟了设计模式-- 发布者/订阅者模式 (包括发布者/订阅者模式和观察者模式的区别)
23種設(shè)計(jì)模式+額外常用設(shè)計(jì)模式匯總 (持續(xù)更新)
發(fā)布-訂閱模式
在軟件架構(gòu)中,發(fā)布訂閱是一種消息范式,消息的發(fā)送者(稱為發(fā)布者)不會(huì)將消息直接發(fā)送給特定的接收者(稱為訂閱者)。而是將發(fā)布的消息分為不同的類別,無需了解哪些訂閱者(如果有的話)可能存在。同樣的,訂閱者可以表達(dá)對(duì)一個(gè)或多個(gè)類別的興趣,只接收感興趣的消息,無需了解哪些發(fā)布者(如果有的話)存在。
舉個(gè)報(bào)紙的例子:
還是得說一下報(bào)紙,有人說報(bào)紙不就是觀察者模式,那得有多少觀察者和主題?一張報(bào)紙那么多板塊,訂報(bào)紙的人那么多,難道要一個(gè)人一個(gè)人的通知,顯然不現(xiàn)實(shí)。如果在記者(編輯)和讀者之間加了一個(gè)載體報(bào)紙,那么這還是觀察者模式嗎?
無數(shù)的編輯將新聞發(fā)到報(bào)設(shè),報(bào)社在將信息整合到報(bào)紙同意發(fā)送到讀者手中,顯然這不是觀察者模式,觀察者模式中,觀察者和主題有著很強(qiáng)的耦合性,而在這里顯然記者不認(rèn)識(shí)讀者,讀者也不能通過報(bào)紙直接和編輯通信,這就是發(fā)布者訂閱者模式,簡單來說和發(fā)布者的區(qū)別就是多了一家報(bào)社。興許我這樸實(shí)的例子并不能讓你看明白,我們看一下國外的大佬怎么說?
觀察者模式和發(fā)布訂閱模式有什么區(qū)別?
之前我的回答是《Head First設(shè)計(jì)模式》里講的:Publishers + Subscribers = Observer Pattern 而且GoF也說只是別稱。但是眾說紛紜,可能看問題的觀點(diǎn)不同,前人是大佬,后人也要用發(fā)展性的眼觀看待,我么就來看看這兩種設(shè)計(jì)模式到底有什么區(qū)別。
首先我們來重新來回顧一下觀察者模式:
觀察者模式定義了對(duì)象之間的一對(duì)多依賴,這樣一來,當(dāng)一個(gè)對(duì)象改變狀態(tài)時(shí),它的所有依賴者都會(huì)收到通知并自動(dòng)更新。而觀察者模式屬于行為型模式,行為型模式關(guān)注的是對(duì)象之間的通訊,觀察者模式就是觀察者和被觀察者之間的通訊。
由上圖可以詳細(xì)的看出觀察者和被觀察者是密切聯(lián)系的。
我們?cè)賮砜纯窗l(fā)布者-訂閱者模式
在“發(fā)布者-訂閱者”模式中,稱為發(fā)布者的消息發(fā)送者不會(huì)將消息編程為直接發(fā)送給稱為訂閱者的特定接收者。這意味著發(fā)布者和訂閱者不知道彼此的存在。存在第三個(gè)組件,稱為代理或消息代理或事件總線,它由發(fā)布者和訂閱者都知道,它過濾所有傳入的消息并相應(yīng)地分發(fā)它們。換句話說,pub-sub是用于在不同系統(tǒng)組件之間傳遞消息的模式,而這些組件不知道關(guān)于彼此身份的任何信息。經(jīng)紀(jì)人如何過濾所有消息?實(shí)際上,有幾個(gè)消息過濾過程。最常用的方法有:基于主題和基于內(nèi)容的。
我們放幾張圖,方便理解:
總結(jié)出的差異
- 在觀察者模式中,觀察者知道主題,主題也維護(hù)觀察者的記錄。而在發(fā)布者/訂閱者中,發(fā)布者和訂閱者不需要彼此了解。他們只是在消息隊(duì)列或代理的幫助下進(jìn)行通信。
- 在發(fā)布者/訂閱者模式中,與觀察者模式相反,組件是松散耦合的。
- 觀察者模式大多數(shù)是以同步方式實(shí)現(xiàn)的,即,當(dāng)某個(gè)事件發(fā)生時(shí),主題調(diào)用其所有觀察者的適當(dāng)方法。的發(fā)行者/訂戶圖案在一個(gè)實(shí)施大多異步方式(使用消息隊(duì)列)。
- 觀察者模式需要在單個(gè)應(yīng)用程序地址空間中實(shí)現(xiàn)。另一方面,發(fā)布者/訂閱者模式更多地是跨應(yīng)用程序模式。
盡管這些模式之間存在差異,但有些人可能會(huì)說Publisher-Subscriber模式是Observer模式的變體,因?yàn)樗鼈冎g在概念上相似。而且這根本沒有錯(cuò)。無需認(rèn)真對(duì)待差異。它們是相似的,不是嗎?
注: 上文參考地址:https://hackernoon.com/observer-vs-pub-sub-pattern-50d3b27f838c
優(yōu)點(diǎn):
- 松耦合
發(fā)布者與訂閱者松耦合,甚至不需要知道它們的存在。由于主題才是關(guān)注的焦點(diǎn),發(fā)布者和訂閱者可以對(duì)系統(tǒng)拓?fù)浣Y(jié)構(gòu)保持一無所知。各自繼續(xù)正常操作而無需顧及對(duì)方。 - 可擴(kuò)展性
通過并行操作,消息緩存,基于樹或基于網(wǎng)絡(luò)的路由等技術(shù),發(fā)布/訂閱提供了比傳統(tǒng)的客戶端–服務(wù)器更好的可擴(kuò)展性。
缺點(diǎn):
- 發(fā)布/訂閱系統(tǒng)最嚴(yán)重的問題是其主要優(yōu)點(diǎn)的副作用:發(fā)布者解耦訂閱者。
- 消息交付問題:發(fā)布/訂閱系統(tǒng)必須仔細(xì)設(shè)計(jì),才能提供特定的應(yīng)用程序可能需要的更強(qiáng)大的系統(tǒng)性能,因?yàn)樗神詈?#xff0c;無論訂閱者是否正常收到發(fā)布內(nèi)容,訂閱器都會(huì)停止發(fā)送。
- 訂閱器中的內(nèi)容隨著發(fā)布者使用者的增加服務(wù)器的負(fù)載,對(duì)中介服務(wù)器是極大的考驗(yàn)!
UML圖
具體實(shí)現(xiàn)
別詬病我的中文寫代碼,為了看的更清楚一點(diǎn),因?yàn)椴缓美斫?#xff0c;我看了好久的!
1.發(fā)布者接口
package 發(fā)布者訂閱者模式;public interface I發(fā)布者接口<M> {public void publish(訂閱器 subscribePublish, M message, boolean isInstantMsg);//使用哪個(gè)訂閱器,發(fā)布什么信息 }2.訂閱者者接口
package 發(fā)布者訂閱者模式;public interface I訂閱者接口<M> {public void subcribe(訂閱器 subscribePublish);//從哪個(gè)訂閱器訂閱public void unSubcribe(訂閱器 subscribePublish);//取消訂閱public void update(String publisher, M message);//更新操作,參考觀察者模式 }3.實(shí)際發(fā)布者1
package 發(fā)布者訂閱者模式;public class Ac實(shí)際發(fā)布者<M> implements I發(fā)布者接口<M> {private String name;public Ac實(shí)際發(fā)布者(String name) {super();this.name = name;}public void publish(訂閱器 subscribePublish, M message, boolean isInstantMsg) {subscribePublish.publish(this.name, message, isInstantMsg);} }4.實(shí)際訂閱者1
package 發(fā)布者訂閱者模式;public class Ac實(shí)際訂閱者<M> implements I訂閱者接口<M> {public String name;public Ac實(shí)際訂閱者(String name) {super();this.name = name;}public void subcribe(訂閱器 subscribePublish) {subscribePublish.subcribe(this);}public void unSubcribe(訂閱器 subscribePublish) {subscribePublish.unSubcribe(this);}public void update(String publisher, M message) {System.out.println(this.name + "收到" + publisher + "發(fā)來的消息:" + message.toString());} }5.訂閱信息(報(bào)紙?RSS?微信公眾號(hào)?都是)
package 發(fā)布者訂閱者模式;public class 發(fā)布的信息<M> {private String publisher;private M m;public 發(fā)布的信息(String publisher, M m) {this.publisher = publisher;this.m = m;}public String getPublisher() {return publisher;}public void setPublisher(String publisher) {this.publisher = publisher;}public M getMsg() {return m;}public void setMsg(M m) {this.m = m;} }6.訂閱器
package 發(fā)布者訂閱者模式;import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue;public class 訂閱器<M> {//訂閱器名稱private String name;//訂閱器隊(duì)列容量final int QUEUE_CAPACITY = 300; //最大訂閱器數(shù)量//訂閱器存儲(chǔ)隊(duì)列private BlockingQueue<發(fā)布的信息> queue = new ArrayBlockingQueue<發(fā)布的信息>(QUEUE_CAPACITY);//訂閱者private List<I訂閱者接口> subcribers = new ArrayList<I訂閱者接口>();public 訂閱器(String name) {this.name = name;}public void publish(String publisher, M message, boolean isInstantMsg) {if (isInstantMsg) {update(publisher, message);return;}發(fā)布的信息<M> m = new 發(fā)布的信息<M>(publisher, message);if (!queue.offer(m)) {update();}}public void subcribe(I訂閱者接口 subcriber) {subcribers.add(subcriber);}public void unSubcribe(I訂閱者接口 subcriber) {subcribers.remove(subcriber);}public void update() {發(fā)布的信息 m = null;while ((m = queue.peek()) != null) {this.update(m.getPublisher(), (M) m.getMsg());}}public void update(String publisher, M Msg) {for (I訂閱者接口 subcriber : subcribers) {subcriber.update(publisher, Msg);}} }7.測(cè)試
package 發(fā)布者訂閱者模式;public class MainTest {public static void main(String[] args) {訂閱器<String> subscribePublish = new 訂閱器<String>("報(bào)紙訂閱平臺(tái)");I發(fā)布者接口<String> publisher1 = new Ac實(shí)際發(fā)布者<String>("紐約時(shí)報(bào)");I訂閱者接口<String> subcriber1 = new Ac實(shí)際訂閱者<String>("特朗普");I訂閱者接口<String> subcriber2 = new Ac實(shí)際訂閱者<String>("普京");subcriber1.subcribe(subscribePublish);subcriber2.subcribe(subscribePublish);publisher1.publish(subscribePublish, "美國新型冠狀病毒爆發(fā)的原因", true);publisher1.publish(subscribePublish, "竟然是", true);publisher1.publish(subscribePublish, "川普不作為", false);} }寫在最后:
我叫風(fēng)骨散人,名字的意思是我多想可以不低頭的自由生活,可現(xiàn)實(shí)卻不是這樣。家境貧寒,總得向這個(gè)世界低頭,所以我一直在奮斗,想改變我的命運(yùn)給親人好的生活,希望同樣被生活綁架的你可以通過自己的努力改變現(xiàn)狀,深知成年人的世界里沒有容易二字。目前是一名在校大學(xué)生,預(yù)計(jì)考研,熱愛編程,熱愛技術(shù),喜歡分享,知識(shí)無界,希望我的分享可以幫到你!
如果有什么想看的,可以私信我,如果在能力范圍內(nèi),我會(huì)發(fā)布相應(yīng)的博文!
感謝大家的閱讀!😘你的點(diǎn)贊、收藏、關(guān)注是對(duì)我最大的鼓勵(lì)!
總結(jié)
以上是生活随笔為你收集整理的『设计模式』80年代的人们就已经领悟了设计模式-- 发布者/订阅者模式 (包括发布者/订阅者模式和观察者模式的区别)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学数据库你竟然不用用JAVA写代码,可惜
- 下一篇: 『设计模式』设计模式--策略模式