前言
時間飛逝默勾,轉(zhuǎn)眼初夏已過碉渡,尤記得以前讀大學(xué)的時候,夏季最快樂的時光就是和小伙伴們在球場上打完球后去校門附近的燒烤攤擼串喝酒灾测,那種感覺真是大快人心,怎一個爽字了得垦巴。不過有時也會遇到特殊情況媳搪,在擼串時攤主突然告知要收攤,連忙向我們賠禮道歉骤宣,原因是城管將至秦爆。我們無奈只能中斷擼串過程,帶著無法盡興的郁悶心情離開.......
好吧憔披,扯遠(yuǎn)了等限,說那么多廢話也是想介紹兩個角色,城管和燒烤攤主芬膝,這兩個角色其實就相當(dāng)于觀察者模式中的被觀察者和觀察者望门,他們的活動過程其實就類似于觀察者模式。
觀察者模式
開始介紹觀察者模式锰霜,毫無疑問筹误,先說下它的定義。
定義
定義對象間一種一對多的依賴關(guān)系癣缅,使得每當(dāng)一個對象改變狀態(tài)厨剪,則所有依賴于它的對象都會得到通知并被自動更新。
其實就是發(fā)布-訂閱模式友存,在實際的項目中非常的常見祷膳,比如微信公眾號的消息推送就是觀察者模式的最直接的應(yīng)用。
通用類圖
上面的類圖包含了四個角色屡立,分別是:
Subject 抽象被觀察者:定義被觀察者必須實現(xiàn)的職責(zé)直晨,它必須能夠動態(tài)地增加、取消觀察者膨俐。它一般是抽象類或者是實現(xiàn)類抡秆,僅僅完成作為被觀察者必須實現(xiàn)的職責(zé):管理觀察者并通知觀察者。
Observer 抽象觀察者:為所有的具體觀察者定義一個接口吟策,在得到主題通知時更新自己儒士。
ConcreteSubject 具體被觀察者:定義被觀察者自己的業(yè)務(wù)邏輯,同時定義對哪些事件進行通知檩坚。
ConcreteObserver 具體觀察者:實現(xiàn)抽象觀察者角色所需要的更新接口着撩,各個觀察者有自己的處理邏輯诅福。
實際例子
講完了觀察者模式的角色后,我們用實戰(zhàn)例子來演示一下拖叙,就拿城管和小攤攤主舉例好了氓润,城管對應(yīng)著觀察者模式中的被觀察者,而攤主就對應(yīng)著觀察者薯鳍。OK咖气,角色分配好了,我們開始寫代碼吧挖滤。
抽象被觀察者
public abstract class Subject {
//定義一個觀察者數(shù)組
private List<Observer> obs = new ArrayList<>();
//增加一個觀察者
public void addObserver(Observer o) {
this.obs.add(o);
}
//刪除一個觀察者
public void delObserver(Observer o) {
this.obs.remove(o);
}
//通知所有觀察者
public void notifyObservers() {
for (Observer o : this.obs) {
o.update();
}
}
}
具體被觀察者
也就是城管崩溪,不知道英文怎么拼,用Police代替了斩松,
public class Police extends Subject {
public void chase(){
System.out.println("城管:我要來了伶唯,還不走");
// 通知所有觀察者
notifyObservers();
}
}
抽象觀察者
public interface Observer {
/**
* 通知更新
* @param message
*/
void update(String message);
}
具體觀察者
public class Vendor implements Observer {
private String name;
private String message;
public Vendor(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " 收到: " + message);
}
}
場景類
最后用一個場景類驗證一下,
public class Client {
public static void main(String[] args) {
// 城管--被觀察者
Police police = new Police();
// 燒烤攤主--觀察者
Observer barbecueVendor = new Vendor("燒烤攤主");
// 手抓餅攤主--觀察者
Observer cakeVendor = new Vendor("手抓餅攤主");
System.out.println("=======增加兩個觀察者=======");
police.addObserver(barbecueVendor);
police.addObserver(cakeVendor);
police.chase();
System.out.println("=======刪除一個觀察者=======");
police.delObserver(cakeVendor);
police.chase();
}
}
定義一個城管對象和兩個攤主對象惧盹,然后執(zhí)行通知更新的操作乳幸,結(jié)果如下:
=======增加兩個觀察者=======
城管:我要來了,還不走
燒烤攤主 收到: 城管要來了钧椰,大家跑啊
手抓餅攤主 收到: 城管要來了粹断,大家跑啊
=======刪除一個觀察者=======
城管:我要來了,還不走
燒烤攤主 收到: 城管要來了嫡霞,大家跑啊
可以看到姿染,我們的代碼能正常增刪觀察者角色,同時也能通知消息更新秒际,也算是重現(xiàn)了了觀察者模式的流轉(zhuǎn)過程悬赏。
總結(jié)
優(yōu)點
1、觀察者和被觀察者之間抽象耦合娄徊。不管是增加觀察者還是被觀察者都非常容易擴展闽颇,而且在Java中都已經(jīng)實現(xiàn)的抽象層級的定義,在系統(tǒng)擴展方面更是得心應(yīng)手寄锐。
2兵多、對象之間的保持高度的協(xié)作。當(dāng)被觀察者發(fā)生變化時橄仆,所有被觀察者都會通知到剩膘,然后做出相應(yīng)的動作。
缺點
1盆顾、如果觀察者太多怠褐,被觀察者通知觀察者消耗的時間很多,同時開發(fā)和調(diào)試會比較復(fù)雜您宪,影響系統(tǒng)的性能奈懒。
2奠涌、在Java中消息的通知默認(rèn)是順序執(zhí)行,當(dāng)某一觀察者錯誤時就會導(dǎo)致系統(tǒng)卡殼磷杏,因此一般會采用異步方式溜畅。
參考:
《設(shè)計模式之禪》