1.概述
定義:
又被稱為發(fā)布-訂閱(Publish/Subscribe)模式,它定義了一種一對多的依賴關(guān)系,讓多個觀察者對象同時監(jiān)聽某一個主題對象。這個主題對象在狀態(tài)變化時,會通知所有的觀察者對象,使他們能夠自動更新自己。
2.結(jié)構(gòu)
在觀察者模式中有如下角色:
- Subject:抽象主題(抽象被觀察者),抽象主題角色把所有觀察者對象保存在一個集合里,每個主題都可以有任意數(shù)量的觀察者,抽象主題提供一個接口,可以增加和刪除觀察者對象。
- ConcreteSubject:具體主題(具體被觀察者),該角色將有關(guān)狀態(tài)存入具體觀察者對象,在具體主題的內(nèi)部狀態(tài)發(fā)生改變時,給所有注冊過的觀察者發(fā)送通知。
- Observer:抽象觀察者,是觀察者的抽象類,它定義了一個更新接口,使得在得到主題更改通知時更新自己。
- ConcrereObserver:具體觀察者,實現(xiàn)抽象觀察者定義的更新接口,以便在得到主題更改通知時更新自身的狀態(tài)。
3.案例實現(xiàn)
【例】微信公眾號
在使用微信公眾號時,大家都會有這樣的體驗,當(dāng)你關(guān)注的公眾號中有新內(nèi)容更新的話,它就會推送給關(guān)注公眾號的微信用戶端。我們使用觀察者模式來模擬這樣的場景,微信用戶就是觀察者,微信公眾號是被觀察者,有多個的微信用戶關(guān)注了程序猿這個公眾號。
類圖如下:
代碼如下:
定義抽象觀察者類,里面定義一個更新的方法
public interface Observer {
void update(String message);
}
定義具體觀察者類,微信用戶是觀察者,里面實現(xiàn)了更新的方法
public class WeixinUser implements Observer {
// 微信用戶名
private String name;
public WeixinUser(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + "-" + message);
}
}
定義抽象主題類,提供了attach、detach、notify三個方法
public interface Subject {
//增加訂閱者
public void attach(Observer observer);
//刪除訂閱者
public void detach(Observer observer);
//通知訂閱者更新消息
public void notify(String message);
}
微信公眾號是具體主題(具體被觀察者),里面存儲了訂閱該公眾號的微信用戶,并實現(xiàn)了抽象主題中的方法
public class SubscriptionSubject implements Subject {
//儲存訂閱公眾號的微信用戶
private List<Observer> weixinUserlist = new ArrayList<Observer>();
@Override
public void attach(Observer observer) {
weixinUserlist.add(observer);
}
@Override
public void detach(Observer observer) {
weixinUserlist.remove(observer);
}
@Override
public void notify(String message) {
for (Observer observer : weixinUserlist) {
observer.update(message);
}
}
}
客戶端程序
public class Client {
public static void main(String[] args) {
SubscriptionSubject mSubscriptionSubject=new SubscriptionSubject();
//創(chuàng)建微信用戶
WeixinUser user1=new WeixinUser("孫悟空");
WeixinUser user2=new WeixinUser("豬悟能");
WeixinUser user3=new WeixinUser("沙悟凈");
//訂閱公眾號
mSubscriptionSubject.attach(user1);
mSubscriptionSubject.attach(user2);
mSubscriptionSubject.attach(user3);
//公眾號更新發(fā)出消息給訂閱的微信用戶
mSubscriptionSubject.notify("傳智黑馬的專欄更新了");
}
}
4.優(yōu)缺點
1,優(yōu)點:
- 降低了目標(biāo)與觀察者之間的耦合關(guān)系,兩者之間是抽象耦合關(guān)系。
- 被觀察者發(fā)送通知,所有注冊的觀察者都會收到信息【可以實現(xiàn)廣播機(jī)制】
2,缺點:
- 如果觀察者非常多的話,那么所有的觀察者收到被觀察者發(fā)送的通知會耗時
- 如果被觀察者有循環(huán)依賴的話,那么被觀察者發(fā)送通知會使觀察者循環(huán)調(diào)用,會導(dǎo)致系統(tǒng)崩潰
5.使用場景
- 對象間存在一對多關(guān)系,一個對象的狀態(tài)發(fā)生改變會影響其他對象。
- 當(dāng)一個抽象模型有兩個方面,其中一個方面依賴于另一方面時。
6.JDK中提供的實現(xiàn)
在 Java 中,通過 java.util.Observable 類和 java.util.Observer 接口定義了觀察者模式,只要實現(xiàn)它們的子類就可以編寫觀察者模式實例。
1,Observable類
Observable 類是抽象目標(biāo)類(被觀察者),它有一個 Vector 集合成員變量,用于保存所有要通知的觀察者對象,下面來介紹它最重要的 3 個方法。
- void addObserver(Observer o) 方法:用于將新的觀察者對象添加到集合中。
- void notifyObservers(Object arg) 方法:調(diào)用集合中的所有觀察者對象的 update方法,通知它們數(shù)據(jù)發(fā)生改變。通常越晚加入集合的觀察者越先得到通知。
- void setChange() 方法:用來設(shè)置一個 boolean 類型的內(nèi)部標(biāo)志,注明目標(biāo)對象發(fā)生了變化。當(dāng)它為true時,notifyObservers() 才會通知觀察者。
2,Observer 接口
Observer 接口是抽象觀察者,它監(jiān)視目標(biāo)對象的變化,當(dāng)目標(biāo)對象發(fā)生變化時,觀察者得到通知,并調(diào)用 update 方法,進(jìn)行相應(yīng)的工作。
【例】警察抓小偷
警察抓小偷也可以使用觀察者模式來實現(xiàn),警察是觀察者,小偷是被觀察者。代碼如下:
小偷是一個被觀察者,所以需要繼承Observable類
public class Thief extends Observable {
private String name;
public Thief(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void steal() {
System.out.println("小偷:我偷東西了,有沒有人來抓我?。?!");
super.setChanged(); //changed = true
super.notifyObservers();
}
}
警察是一個觀察者,所以需要讓其實現(xiàn)Observer接口文章來源:http://www.zghlxwxcb.cn/news/detail-421684.html
public class Policemen implements Observer {
private String name;
public Policemen(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println("警察:" + ((Thief) o).getName() + ",我已經(jīng)盯你很久了,你可以保持沉默,但你所說的將成為呈堂證供?。。?);
}
}
客戶端代碼文章來源地址http://www.zghlxwxcb.cn/news/detail-421684.html
public class Client {
public static void main(String[] args) {
//創(chuàng)建小偷對象
Thief t = new Thief("隔壁老王");
//創(chuàng)建警察對象
Policemen p = new Policemen("小李");
//讓警察盯著小偷
t.addObserver(p);
//小偷偷東西
t.steal();
}
}
到了這里,關(guān)于設(shè)計模式:行為型模式 - 觀察者模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!