定義
觀察者模式也叫訂閱-發(fā)布者模式,是一種一對(duì)一或者一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象改變狀態(tài),依賴它的對(duì)象會(huì)收到通知并自動(dòng)更新。
觀察者模式的結(jié)構(gòu)
觀察者模式主要由四個(gè)主要部分構(gòu)成
(1)主題(Subject):主題也叫抽象被觀察者,是一個(gè)接口,該接口規(guī)定了具體主題需要實(shí)現(xiàn)的方法,比如,添加、刪除觀察者以及通知觀察者更新數(shù)據(jù)的抽象方法。
(2)觀察者(Observer):觀察者是一個(gè)接口,該接口規(guī)定了具體觀察者用來更新數(shù)據(jù)的方法。
(3)具體主題(ConcreteSubject):具體主題也叫具體被觀察者,是實(shí)現(xiàn)主題接口類的一個(gè)實(shí)例,該實(shí)例包含有可以經(jīng)常發(fā)生變化的數(shù)據(jù)。具體主題需使用一個(gè)集合,比如ArrayList,存放觀察者的引用,以便數(shù)據(jù)變化時(shí)及時(shí)通知具體觀察者。
(4)具體觀察者(ConcreteObserver):實(shí)現(xiàn)抽象觀察者角色所需要的更新接口,對(duì)具體主題通知做出改變。
通俗點(diǎn)就是:主題發(fā)布信息,觀察者獲取信息,他們關(guān)聯(lián)了就能收到信息,沒有關(guān)聯(lián)就收不到信息。
如圖:

觀察者模式的適用的場(chǎng)景
如果你想一個(gè)對(duì)象的數(shù)據(jù)更新時(shí)需要通知其他對(duì)象,讓其他對(duì)象對(duì)通知做出改變,那么觀察者模式比較實(shí)用。
代碼部分
場(chǎng)景:假設(shè)張三和李四買彩票,時(shí)刻關(guān)注彩票中心的消息,其中一個(gè)人中獎(jiǎng),很高興,另一個(gè)人不開心,取消了對(duì)彩票中心的關(guān)注,就再也收不到彩票中心的消息了。
在這個(gè)模擬中彩票中心就是主題(Subject),張三和李四就是觀察彩票中心消息的具體觀察者(ConcreteObserver)。對(duì)彩票消息做出行為。
Subject接口相關(guān)代碼
/**
* 描述:抽象主題(抽象被觀察者)
*/
public interface Subject {
/**
* 注冊(cè)觀察者
* @param observer 觀察者
*/
void registerObserver(Observer observer);
/**
* 移除觀察者
* @param observer 觀察者
*/
void removeObserver(Observer observer);
/**
* 在狀態(tài)發(fā)生變化通知觀察者
*/
void notifyObserver(String message);
}
Observer接口相關(guān)代碼
/**
* 描述:抽象觀察者
*/
public interface Observer {
/**
* 當(dāng)被觀察者調(diào)用notifyObservers()方法時(shí),觀察者的update()方法會(huì)被回調(diào)。
* @param message 通知內(nèi)容
*/
void update(ConcreteObserver observer,String message);
}
ConcreteSubject類相關(guān)代碼
/**
* 描述:具體主題實(shí)現(xiàn)類
*/
public class ConcreteSubject implements Subject {
//創(chuàng)建集合用來存放觀察者對(duì)象
List<Observer> mObserverList;
public ConcreteSubject() {
mObserverList = new LinkedList<>();
}
//注冊(cè)觀察者,也就是將觀察者放到集合中
@Override
public void registerObserver(Observer observer) {
mObserverList.add(observer);
}
//移除觀察者,也就是將觀察者從集合中移除
@Override
public void removeObserver(Observer observer) {
mObserverList.remove(observer);
}
//狀態(tài)改變,通知觀察者
@Override
public void notifyObserver(String message) {
//遍歷通知所有觀察者
for(int i =0;i<mObserverList.size();i++){
//此處進(jìn)行了強(qiáng)轉(zhuǎn)
mObserverList.get(i).update((ConcreteObserver)mObserverList.get(i),message);
}
}
/**
* 通知內(nèi)容
* @param message
*/
public void sendMessage(String message){
notifyObserver(message);
}
}
ConcreteObserver類相關(guān)代碼
/**
* 描述:具體觀察者,對(duì)Subject的通知執(zhí)行具體操作
*/
public class ConcreteObserver implements Observer {
private static final String TAG = "ConcreteObserver";
//用戶名
String name;
//中獎(jiǎng)號(hào)碼
String number;
public ConcreteObserver(String name,String work) {
this.name = name;
this.number=work;
}
@Override
public void update(ConcreteObserver observer,String message) {
if(observer.number.equals(message)){
Log.e(TAG, observer.name+"的號(hào)碼是:" +observer.number+"中獎(jiǎng)號(hào)碼是"+message+"他很高興");
}else{
Log.e(TAG, observer.name+"的號(hào)碼是:" +observer.number+"中獎(jiǎng)號(hào)碼是"+message+"不很高興");
}
}
}
測(cè)試相關(guān)代碼
//創(chuàng)建主題實(shí)例
ConcreteSubject concreteSubject =new ConcreteSubject();
ConcreteObserver zhansan =new ConcreteObserver("張三","111111");
ConcreteObserver lisi =new ConcreteObserver("李四","222222");
concreteSubject.registerObserver(zhansan);
concreteSubject.registerObserver(lisi);
//設(shè)置中獎(jiǎng)號(hào)碼
concreteSubject.sendMessage("111111");
//移除觀察者李四
concreteSubject.removeObserver(lisi);
//設(shè)置中獎(jiǎng)號(hào)碼
concreteSubject.sendMessage("222222");
測(cè)試結(jié)果:

雖然現(xiàn)在觀察者模式不常用了,更多人選擇Rx等框架實(shí)現(xiàn)即時(shí)更新,但我們一定要理解其本質(zhì)和核心思想。