使用場(chǎng)景
- 一個(gè)抽象模型有兩個(gè)方面蒋荚,其中一個(gè)方面依賴于另一個(gè)方面。將這些方面封裝在獨(dú)立的對(duì)象中使它們可以各自獨(dú)立地改變和復(fù)用戈钢。
- 一個(gè)對(duì)象的改變將導(dǎo)致其他一個(gè)或多個(gè)對(duì)象也發(fā)生改變痹仙,而不知道具體有多少對(duì)象將發(fā)生改變,可以降低對(duì)象之間的耦合度殉了。
- 一個(gè)對(duì)象必須通知其他對(duì)象开仰,而并不知道這些對(duì)象是誰(shuí)。需要在系統(tǒng)中創(chuàng)建一個(gè)觸發(fā)鏈薪铜,A對(duì)象的行為將影響B(tài)對(duì)象众弓,B對(duì)象的行為將影響C對(duì)象……,可以使用觀察者模式創(chuàng)建一種鏈?zhǔn)接|發(fā)機(jī)制隔箍。
定義
觀察者模式定義了對(duì)象之間的一對(duì)多依賴關(guān)系谓娃,這樣一來(lái),當(dāng)一個(gè)對(duì)象改變狀態(tài)時(shí)蜒滩,它的所有依賴者都會(huì)收到通知并且自動(dòng)更新滨达。
在這里奶稠,發(fā)生改變的對(duì)象稱之為觀察目標(biāo)(subject),而被通知的對(duì)象稱之為觀察者(observer)弦悉。一個(gè)觀察目標(biāo)可以對(duì)應(yīng)多個(gè)觀察者窒典,而且這些觀察者之間沒(méi)有相互聯(lián)系,所以么可以根據(jù)需要增加和刪除觀察者稽莉,使得系統(tǒng)更易于擴(kuò)展瀑志。
觀察者模式又稱為發(fā)布-訂閱模式。
它的靜態(tài)結(jié)構(gòu)圖如下:
-
Subject:主題
他把所有對(duì)觀察者對(duì)戲的引用保存在一個(gè)聚集里污秆,每一個(gè)主題都可以有多個(gè)觀察者劈猪。 -
Observer:觀察者
為所有的具體觀察者定義一個(gè)接口,在得到主題的通知時(shí)能夠及時(shí)的更新自己良拼。 -
ConcreteSubject:具體主題
將有關(guān)狀態(tài)存入具體觀察者對(duì)象战得。在具體主題發(fā)生改變時(shí),給所有的觀察者發(fā)出通知庸推。 -
ConcreteObserver:具體觀察者
實(shí)現(xiàn)抽象觀察者角色所要求的更新接口常侦,以便使本身的狀態(tài)與主題狀態(tài)相協(xié)調(diào)。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 當(dāng)兩個(gè)對(duì)象之間松耦合贬媒,他們依然可以交互聋亡,但是不太清楚彼此的細(xì)節(jié)。觀察者模式提供了一種對(duì)象設(shè)計(jì)际乘,讓主題和觀察者之間松耦合坡倔。主題所知道只是一個(gè)具體的觀察者列表,每一個(gè)具體觀察者都符合一個(gè)抽象觀察者的接口脖含。主題并不認(rèn)識(shí)任何一個(gè)具體的觀察者罪塔,它只知道他們都有一個(gè)共同的接口。
- 觀察者模式支持“廣播通信”养葵。主題會(huì)向所有的觀察者發(fā)出通知征堪。
- 觀察者模式符合“開(kāi)閉原則”的要求。
缺點(diǎn):
- 如果一個(gè)被觀察者對(duì)象有很多的直接和間接的觀察者的話关拒,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間请契。
- 如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴的話,觀察目標(biāo)會(huì)觸發(fā)它們之間進(jìn) 行循環(huán)調(diào)用夏醉,可能導(dǎo)致系統(tǒng)崩潰爽锥。
- 觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對(duì)象是怎么發(fā)生變化的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化畔柔。
具體實(shí)現(xiàn)
通用的實(shí)現(xiàn)模板
- Subject:主題
/*
* 抽象主題類
*
*/
public interface Subject {
public void registerObserver(Observer observer);
public void removeObserver(Observer observer);
public void notifyObservers();
}
- Observer:觀察者
/*
* 抽象觀察者
* 當(dāng)主題狀態(tài)改變時(shí)氯夷,調(diào)用update通知觀察者
*
*/
public interface Observer {
public void update(Subject subject);
}
- ConcreteSubject:具體主題
/*
* 具體主題類
* 實(shí)現(xiàn)主題接口
*
*/
public class ConcreteSubject implements Subject {
// 已注冊(cè)的觀察者名單
private List<Observer> observers = new ArrayList<Observer>();
// 主題狀態(tài)
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
this.notifyObservers();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
// 此處默認(rèn)全部通知更新,可以根據(jù)具體條件通知具體觀察者
for(Observer observer:observers){
observer.update(this);
}
}
}
- ConcreteObserver:具體觀察者
/*
* 具體觀察者類
*
*/
public class ConcreteObserver implements Observer {
private String observerName;
private String observerState;
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
@Override
public void update(Subject subject) {
observerState = ((ConcreteSubject)subject).getSubjectState();
System.out.println("我是觀察者:"+observerName+" 現(xiàn)在的天氣情況為:"+observerState);
}
}
- 測(cè)試類
public class testObserver {
public static void main(String[] args) {
// 創(chuàng)建目標(biāo)
ConcreteSubject subject = new ConcreteSubject();
// 創(chuàng)建觀察者
ConcreteObserver observer1 = new ConcreteObserver();
observer1.setObserverName("小明");
ConcreteObserver observer2 = new ConcreteObserver();
observer2.setObserverName("小紅");
// 注冊(cè)觀察者
subject.registerObserver(observer1);
subject.registerObserver(observer2);
// 改變狀態(tài)靶擦,自動(dòng)通知所有觀察者
subject.setSubjectState("下雨了腮考!");
}
}
兩種獲取數(shù)據(jù)方式
-
推模型
目標(biāo)對(duì)象主動(dòng)向觀察者推送目標(biāo)的詳細(xì)信息
推送的信息通常是目標(biāo)信息的全部或部分信息
上面例子中使用的就是推模型:update(Subject subject) -
拉模型
目標(biāo)對(duì)象在通知觀察者的時(shí)候雇毫,只傳遞少量信息
如果觀察者需要更具體的信息,由觀察者主動(dòng)到目標(biāo)對(duì)象中獲取踩蔚,相當(dāng)于是觀察者從目標(biāo)對(duì)象中拉數(shù)據(jù)
一般這種模型的實(shí)現(xiàn)中棚放,會(huì)把目標(biāo)對(duì)象自身通過(guò)update方法傳遞給觀察者。
如果修改為如下則為拉模型:update(String subjectName)
比較
Tables | 推模型 | 拉模型 |
---|---|---|
數(shù)據(jù) | 具體主題類本身 | 具體主題詳細(xì)信息 |
靈活性 | 較好 | 較差 |