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