這是我參與8月更文挑戰的第9天,活動詳情查看:8月更文挑戰java
歡迎來到今天的學習,今天咱們一塊兒來學習下使用頻率很高且實踐比較多的一種模式----觀察者模式。多嘮叨幾句,我本月將會對java的設計模式精講,歡迎點擊頭像,關注個人專欄,我會持續更新,加油!設計模式
系列文章:微信
設計模式之單例模式markdown
設計模式之工廠模式數據結構
設計模式之訪問者模式ide
設計模式之適配器模式post
...持續更新中
話很少說,進入正題
觀察者模式是一種很是流行的設計模式,也有人稱之爲訂閱-發佈模式,我我的認爲都是一種思想,就是一對象當中,任何的改變,都能被監聽到,識別到,而後去通知改變,這個行爲也能夠稱之爲「事件」,觀察者經過處理每個事件來完成自身的操做處理
觀察者模式的原始定義是:定義對象之間的一對多依賴關係,這樣當一個對象改變狀態時,它的全部依賴項都會自動獲得通知和更新。
注意:該定義當中,對象之間的是一對多,那麼這個一就是觀察者,只有一個觀察者在觀察動態,多即是指被觀察者。咱們還能夠稱觀察者模式爲如下幾種叫法,不過無論怎麼叫,本質都是觀察者模式的思想
事件發佈,事件監聽
發佈者-訂閱者
生產者-消費者
這種模式在各類框架源碼當中也家常便飯,很適合在實踐中運用與巧妙處理。
我之前寫過一篇乾貨實戰文章,就是利用Spring當中的監聽來完成的,有興趣的能夠看下:
迴歸正題,下面看下,觀察者模式的圖(圖片來源於網路)
從上圖中,咱們能看出觀察者模式包含的四個關鍵角色:
1 、發佈者(Publisher),也被叫做主題、被訂閱者、被觀察者等
二、 具體發佈者(PublisherImpl),實現了發佈者定義的方法的具體實現類
三、訂閱者(Observer):也叫做觀察者,它會存儲一個註冊列表,用於存放訂閱者。當發佈者發佈消息或事件時,會通知到訂閱者進行處理。
四、 具體訂閱者(ObserverImpl):實現具體定義的方法操做。
接下來咱們經過一個場景和代碼來讓你深刻理解下:
使用場景分析:
咱們拿微信公衆號推文場景來展現下,咱們都知道咱們的公衆號推文文章只會推送給關注我公衆號的人,那麼,假如我今天發表一篇名爲「java觀察者模式」一篇推文,張三,李四,王五關注了個人公衆號,那麼我點擊發布,就會往他們的微信上推。
咱們首先定義觀察者 ArticleObserver。它只有一個 send 方法,當有文章 Article 發送過來時就會調用該方法。
public interface ArticleObserver {
void send(Articl m);
}
複製代碼
接着再定義文章的具體數據結構,這裏使用一個 content 文章內容。
public class Articl {
final String content;
public Articl (String m) {
this.content = m;
}
public String getContent() {
return content;
}
}
複製代碼
而後,再來定義一個被觀察者 Subject ,它定義了三個方法:增長觀察者方法 attach、刪除觀察者方。
public interface Subject {
void attach(ArticleObserver a); //增長觀察者
void detach(ArticleObserver a); //刪除觀察者
void notifySend(Article m); //異步發送推文
}
複製代碼
再接下來,實現 Subject 的具體發佈者類 ArticlePublisher,它持有一組觀察者 ArticleObserver 實例,能夠經過 attach 和 detach 接口方法新增和刪除觀察者,異步通知發送方法 notifySend
public class ArticlePublisher implements Subject {
private List<ArticleObserver> observers = new ArrayList<>();
@Override
public void attach(ArticleObserver o) {
observers.add(o);
}
@Override
public void detach(ArticleObserver o) {
observers.remove(o);
}
@Override
public void notifySend(Articl m) {
observers.forEach(x->x.sed(m));
}
}
複製代碼
最後,咱們實現三個具體訂閱者類(張三,李四,王五),它們都實現(關注了該公衆號)了 ArticleObserver 接口,分別要發送到三者微信當中。
//張三訂閱
public class ZhangSanSubscriber implements ArticleObserver {
@Override
public void send(Articl a) {
System.out.println("ZhangSanSubscriber 看到 :: " + a.getContent());
}
}
//李四訂閱
public class LisiSubscriber implements ArticleObserver {
@Override
public void send(Articl a) {
System.out.println("LisiSubscriber 看到 :: " + a.getContent());
}
}
//王五訂閱
public class WangwuSubscriber implements ArticleObserver {
@Override
public void send(Articl a) {
System.out.println("WangwuSubscriber 看到 :: " + a.getContent());
}
}
複製代碼
單元測試下:
public class Client {
public static void main(String[] args) {
ArticleObserver zhangSan = new ZhangSanSubscriber();
ArticleObserver liSi = new LisiSubscriber();
ArticleObserver wangWu = new WangwuSubscriber();
Subject p = new ArticlePublisher();
// 增長訂閱,將相應訂閱者添加進去(集合)
p.attach(zhangSan);
p.attach(liSi);
p.attach(wangWu);
//發送推文
p.notifySend(new Articl("java觀察者模式"));
}
}
//輸出結果
ZhangSanSubscriber 看到 :: java觀察者模式
LisiSubscriber 看到 :: java觀察者模式
WangwuSubscriber 看到 :: java觀察者模式
注意,我這裏只是用了一篇文章(發佈對象),能夠多種。
複製代碼
OK,代碼到這裏就結束了。
上面的代碼實現很是簡單,可是充分體現了觀察者模式的使用場景。觀察者模式使用場景的特色在於找到合適的被觀察者,定義一個通知列表,將須要通知的對象放到這個通知列表中,當被觀察者須要發起通知時,就會通知這個列表中的全部「人」。
使用觀察者模式的優勢:
由利用代碼擴展性的提高,因爲觀察者和被觀察之間是抽象耦合,因此擴展性較強
下降系統與系統之間的耦合性,好比,創建訂閱者集合,能夠隨時添加或者刪除該集合當中的某一元素。
有褒有貶:
我我的理解,會下降性能,觀察者模式一般須要事件觸發,當觀察者對象越多時,被觀察者須要通知觀察者所花費的時間也會越長,這樣會在某種程度上影響程序的效率。
看到這裏可能會有夥伴問了,爲何使用觀察者模式?,我認爲有如下兩點:
一、爲了方便捕獲觀察對象的變化並及時作出相應的操做,好比快遞的狀態要及時變動等。
二、上面也說到了,爲了提升代碼的擴展性
感謝你的閱讀,若是你感受學到了東西,麻煩您點贊,關注。
我已經將本章收錄在專題裏,點擊下方專題,關注專欄,我會天天發表乾貨,本月我會持續輸入設計模式。
加油! 咱們下期再見!