觀察者模式介紹
觀察者模式是一個(gè)使用率非常高的模式,它最常用的地方是GUI系統(tǒng)丰榴、訂閱——發(fā)布系統(tǒng)。因?yàn)檫@個(gè)模式的一個(gè)重要的作用就是解耦秆撮,將被觀察和觀察者解耦四濒,使得它們之間的依賴性更小,甚至做到毫無依賴职辨。以GUI系統(tǒng)來說盗蟆,應(yīng)用的UI具有易變性,尤其是前期隨著業(yè)務(wù)的改變或者產(chǎn)品的需求修改拨匆,應(yīng)用界面也會經(jīng)常性變化姆涩,但業(yè)務(wù)邏輯基本變化不大,此時(shí)惭每,GUI系統(tǒng)需要一套機(jī)制來應(yīng)對這種情況骨饿,使得UI層與具體的業(yè)務(wù)邏輯解耦,觀察者模式此時(shí)就派上用場台腥。
觀察者模式的定義
定義對象間一種一對多的依賴關(guān)系宏赘,使得每當(dāng)一個(gè)對象改變狀態(tài),則所有依賴于它的對象都會得到通知并被自動更新黎侈。
觀察者模式的使用場景
- 關(guān)聯(lián)行為場景察署,需要注意的是,關(guān)聯(lián)行為是可拆分的峻汉,而不是“組合”關(guān)系贴汪;
- 事件多級觸發(fā)場景
- 跨系統(tǒng)的消息交換場景脐往,如消息隊(duì)列、事件總線的處理機(jī)制扳埂。
觀察者模式的UML類圖
角色分析
- Observable:抽象主體业簿,被觀察者的角色,抽象主題角色把所有觀察者對象的引用保存在一個(gè)集合里阳懂,每個(gè)主題都可以任意數(shù)量的觀察者梅尤,抽象主題提供一個(gè)接口,可以增加和刪除觀察者對象
- ConcreteSubject:具體主題岩调,該角色將有關(guān)狀態(tài)存入具體觀察者對象巷燥,在具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí),給所有注冊過觀察者發(fā)生通知号枕,具體主題角色又叫做具體觀察者角色缰揪。
- Observer:抽象觀察者,該角色是觀察者的抽象類堕澄,它定義了一個(gè)更新接口邀跃,使得在得到主題的更通知時(shí)更新自己。
- ConceteObserver:具體的觀察者蛙紫,該角色實(shí)現(xiàn)抽象觀察者角色所定義的更新接口,以便在主題的狀態(tài)發(fā)生變化時(shí)更新自身的狀態(tài)途戒。
觀察者模式的簡單實(shí)現(xiàn)
我們都有去圖書館借書的經(jīng)歷坑傅,可能也經(jīng)歷過當(dāng)你想借某本書的時(shí)候,發(fā)現(xiàn)要么被借完了或者這本書圖書館沒進(jìn)喷斋。那你隔幾天再去圖書館唁毒,可能你要的書還書沒有,這樣來回幾趟的是不是很折騰星爪。那有沒有什么好的方法浆西,等你需要某本書時(shí)圖書館剛好有,你再去圖書館呢顽腾?——現(xiàn)實(shí)中近零,你會在圖書管理員做個(gè)登記,留下你的名字抄肖、聯(lián)系方式和你要借的書久信。等這本書可借的時(shí)候,圖書管理員聯(lián)系你漓摩,你再去圖書館裙士,這樣就避免白走一趟。
在用觀察者模式簡單實(shí)現(xiàn):
/**
* 讀者是觀察者
*/
public class Reader implements Observer {
public String name;
public Reader(String name) {
this.name = name;
}
@Override public void update(Observable o, Object arg) {
System.out.println("Hi," + name + ", 圖書館 更新啦管毙,內(nèi)容 :" + arg);
}
@Override public String toString() {
return "Reader{" +
"name='" + name + '\'' +
'}';
}
}
/**
* Library 這個(gè)圖書館是被觀察者角色腿椎,當(dāng)它有更新時(shí)所有的觀察者(這里就 是讀者)
*/
public class Library extends Observable {
public void postNewPublication(String content) {
//標(biāo)示狀態(tài)活者內(nèi)容發(fā)生改變
setChanged();
//通知所有觀察者
notifyObservers(content);
}
}
/**
* 測試代碼
*/
public class TestOb {
public static void main(String[] args) {
//被觀察的角色
Library deTechFrontier = new Library();
/*觀察者*/
Reader reader1 = new Reader("小吳");
Reader reader2 = new Reader("小劉");
Reader reader3 = new Reader("小崔");
/*將觀察者注冊到可觀察者對象*/
deTechFrontier.addObserver(reader1);
deTechFrontier.addObserver(reader2);
deTechFrontier.addObserver(reader3);
//發(fā)布消息
deTechFrontier.postNewPublication("您訂閱的新書來了");
}
}
輸出結(jié)果
Hi,小崔, 圖書館 更新啦桌硫,內(nèi)容 :您訂閱的新書來了
Hi,小劉, 圖書館 更新啦,內(nèi)容 :您訂閱的新書來了
Hi,小吳, 圖書館 更新啦啃炸,內(nèi)容 :您訂閱的新書來了
Process finished with exit code 0
Observer和Observable是JDK中內(nèi)置類型鞍泉,可見觀察者模式是非常重要的,這里Observer是抽象的觀察者模式角色肮帐,Reader扮演的具體觀察者角色咖驮;Observable對應(yīng)的是抽象主題角色,Library則是具體的主題角色训枢。Reader訂閱了Library對象托修,當(dāng)Library更新的時(shí),會遍歷所有觀察者恒界,然后給這些觀察者發(fā)布一個(gè)更新消息睦刃。
風(fēng)后面是風(fēng),天空上面是天空十酣,而你的生活可以與眾不同