java設(shè)計(jì)模式之觀察者模式
觀察者模式又稱發(fā)布-訂閱(Publish/Subscribe)模式,定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象。這個(gè)主題對(duì)象在狀態(tài)發(fā)生變化時(shí),會(huì)通知所有觀察者對(duì)象,使他們能夠自動(dòng)更新自己。將一個(gè)系統(tǒng)分割成一系列相互協(xié)作的類有一個(gè)很不好的副作用,那就是需要維護(hù)相關(guān)對(duì)象間的一致性。我們不希望為了維持一致性而使各類緊密耦合,這樣會(huì)給維護(hù)、擴(kuò)展和復(fù)用都帶來不便。觀察者模式所做的工作其實(shí)就是在解除耦合,讓耦合的雙方都依賴于抽象,而不是依賴于具體。
觀察者模式是實(shí)際中應(yīng)用比較廣泛的模式,其應(yīng)用場(chǎng)景比如,一臺(tái)生產(chǎn)大米的工廠,和n個(gè)銷售大米的商家,n個(gè)商家首先在這個(gè)工廠注冊(cè)一下自身的聯(lián)系方式,當(dāng)工廠生產(chǎn)出一定量的大米后,再依照聯(lián)系方式通知這n個(gè)商家來取貨。這個(gè)例子當(dāng)中用到了觀察者模式中的注冊(cè)(Attach)和通知(Notify),即當(dāng)通知者的狀態(tài)改變時(shí),依次通知各個(gè)觀察者。
Subject是抽象通知者,Observer是抽象觀察者。如果要?jiǎng)?chuàng)建的派生類是風(fēng)馬牛不相及的對(duì)象,可以考慮使用接口實(shí)現(xiàn)若干個(gè)相同的方法?! ?/p>
Java代碼如下:
abstract class Subject { private ArrayList<Observer> observersList = new ArrayList<Observer>(); // add observers public void Attach(Observer ob) { observersList.add(ob); } // remove observers public void Detach(Observer ob) { observersList.remove(ob); } public void Notify() { for (Observer ob : observersList) { ob.Update(); } } } abstract class Observer { public abstract void Update(); } public class ConcreteObserver extends Observer { private String name; private String observerStatus; private ConcreteSubject subject; public ConcreteObserver(ConcreteSubject subject, String name) { this.subject = subject; this.name = name; } public void Update() { observerStatus = subject.getSubjectStatus(); } } public class ConcreteSubject extends Subject { private String subjectStatus; public String getSubjectStatus() { return subjectStatus; } public void setSubjectStatus(String subjectStatus) { this.subjectStatus = subjectStatus; } public static void main(String[] args) { // TODO Auto-generated method stub ConcreteSubject s = new ConcreteSubject(); s.Attach(new ConcreteObserver(s, "X")); s.Attach(new ConcreteObserver(s, "Y")); s.Attach(new ConcreteObserver(s, "Z")); s.setSubjectStatus("Ready"); s.Notify(); } }
上述代碼中,有抽象觀察者和抽象通知者。當(dāng)Subject的狀態(tài)改變之后,調(diào)用函數(shù)即可通知在其內(nèi)部注冊(cè)過的觀察者。這種設(shè)計(jì)的思想在平時(shí)生活中也是比較常見的,就比如開頭提到的生產(chǎn)大米的廠家和銷售大米的商家。再來一個(gè)應(yīng)用場(chǎng)景,比如書店中某一本書缺貨了,顧客還是想買的話,可以進(jìn)行登記,等到貨后,書店老板會(huì)打電話依次通知想買書的顧客。這種注冊(cè)的機(jī)制在其他的編程技巧中也是有很多體現(xiàn)的。比如程序向底層庫(kù)注冊(cè)多個(gè)回調(diào)函數(shù),當(dāng)條件滿足時(shí),底層庫(kù)就會(huì)通知(或者說調(diào)用)最上層提供的回調(diào)函數(shù)。
上述代碼是Java寫的,C++的話也是類似,主要是Subject保存Observer的指針。但是C++要考慮釋放內(nèi)存的問題,注意當(dāng)Observer本身要被銷毀時(shí),必須要調(diào)用Subject的Detach函數(shù),否則Update時(shí)可能會(huì)出現(xiàn)使用野指針造成crash的問題??梢钥紤]使用Subject管理Observer的生命周期。
相關(guān)文章
TransactionSynchronization的invokeAfterCompletion事務(wù)源碼解析
這篇文章主要為大家介紹了TransactionSynchronization的invokeAfterCompletion事務(wù)源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09SSH框架網(wǎng)上商城項(xiàng)目第15戰(zhàn)之線程、定時(shí)器同步首頁數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了SSH框架網(wǎng)上商城項(xiàng)目第15戰(zhàn)之線程、定時(shí)器同步首頁數(shù)據(jù),感興趣的小伙伴們可以參考一下2016-06-06Java 數(shù)據(jù)結(jié)構(gòu)之堆的概念與應(yīng)用
堆是一顆完全二叉樹,在這棵樹中,所有父節(jié)點(diǎn)都滿足大于等于其子節(jié)點(diǎn)的堆叫大根堆,所有父節(jié)點(diǎn)都滿足小于等于其子節(jié)點(diǎn)的堆叫小根堆,堆雖然是一顆樹,但是通常存放在一個(gè)數(shù)組中,父節(jié)點(diǎn)和孩子節(jié)點(diǎn)的父子關(guān)系通過數(shù)組下標(biāo)來確定2021-10-10關(guān)于SpringBoot微服務(wù)發(fā)布與部署的三種方式
SpringBoot 框架只提供了一套基于可執(zhí)行 jar 包(executable jar)格式的標(biāo)準(zhǔn)發(fā)布形式,但并沒有對(duì)部署做過多的界定,而且為了簡(jiǎn)化可執(zhí)行 jar 包的生成,SpringBoot 提供了相應(yīng)的 Maven 項(xiàng)目插件,需要的朋友可以參考下2023-05-05Java生成獨(dú)一無二的工單號(hào)實(shí)例
這篇文章主要介紹了Java生成獨(dú)一無二的工單號(hào)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-09-09