java設(shè)計(jì)模式之觀察者模式
觀察者模式又稱發(fā)布-訂閱(Publish/Subscribe)模式,定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(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ù)用都帶來(lái)不便。觀察者模式所做的工作其實(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è)商家來(lái)取貨。這個(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è)相同的方法。

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è)過(guò)的觀察者。這種設(shè)計(jì)的思想在平時(shí)生活中也是比較常見(jiàn)的,就比如開(kāi)頭提到的生產(chǎn)大米的廠家和銷售大米的商家。再來(lái)一個(gè)應(yīng)用場(chǎng)景,比如書(shū)店中某一本書(shū)缺貨了,顧客還是想買的話,可以進(jìn)行登記,等到貨后,書(shū)店老板會(huì)打電話依次通知想買書(shū)的顧客。這種注冊(cè)的機(jī)制在其他的編程技巧中也是有很多體現(xiàn)的。比如程序向底層庫(kù)注冊(cè)多個(gè)回調(diào)函數(shù),當(dāng)條件滿足時(shí),底層庫(kù)就會(huì)通知(或者說(shuō)調(diào)用)最上層提供的回調(diào)函數(shù)。
上述代碼是Java寫(xiě)的,C++的話也是類似,主要是Subject保存Observer的指針。但是C++要考慮釋放內(nèi)存的問(wèn)題,注意當(dāng)Observer本身要被銷毀時(shí),必須要調(diào)用Subject的Detach函數(shù),否則Update時(shí)可能會(huì)出現(xiàn)使用野指針造成crash的問(wèn)題。可以考慮使用Subject管理Observer的生命周期。
相關(guān)文章
TransactionSynchronization的invokeAfterCompletion事務(wù)源碼解析
這篇文章主要為大家介紹了TransactionSynchronization的invokeAfterCompletion事務(wù)源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
SSH框架網(wǎng)上商城項(xiàng)目第15戰(zhàn)之線程、定時(shí)器同步首頁(yè)數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了SSH框架網(wǎng)上商城項(xiàng)目第15戰(zhàn)之線程、定時(shí)器同步首頁(yè)數(shù)據(jù),感興趣的小伙伴們可以參考一下2016-06-06
Java 數(shù)據(jù)結(jié)構(gòu)之堆的概念與應(yīng)用
堆是一顆完全二叉樹(shù),在這棵樹(shù)中,所有父節(jié)點(diǎn)都滿足大于等于其子節(jié)點(diǎn)的堆叫大根堆,所有父節(jié)點(diǎn)都滿足小于等于其子節(jié)點(diǎn)的堆叫小根堆,堆雖然是一顆樹(shù),但是通常存放在一個(gè)數(shù)組中,父節(jié)點(diǎn)和孩子節(jié)點(diǎn)的父子關(guān)系通過(guò)數(shù)組下標(biāo)來(lái)確定2021-10-10
關(guān)于SpringBoot微服務(wù)發(fā)布與部署的三種方式
SpringBoot 框架只提供了一套基于可執(zhí)行 jar 包(executable jar)格式的標(biāo)準(zhǔn)發(fā)布形式,但并沒(méi)有對(duì)部署做過(guò)多的界定,而且為了簡(jiǎn)化可執(zhí)行 jar 包的生成,SpringBoot 提供了相應(yīng)的 Maven 項(xiàng)目插件,需要的朋友可以參考下2023-05-05
Java生成獨(dú)一無(wú)二的工單號(hào)實(shí)例
這篇文章主要介紹了Java生成獨(dú)一無(wú)二的工單號(hào)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-09-09

