觀察者模式:
什麼是觀察者模式(Observer Pattern)?這裏我們舉個栗子:一隊警察部署在不同的位置觀察着犯罪分子的活動,當犯罪分子進行某個特定的行爲時,比如進行非法交易的時候,這隊在不同位置的警察同時出擊抓捕罪犯。這就是一種觀察者模式的詮釋。
觀察者模式定義了一種一對多的依賴關係,當被觀察者的狀態發生改變時,所有依賴於它的觀察者對象都會得到通知並作出自己的改變。這是一種行爲型模式。
觀察者主要有三大要素:被觀察對象、觀察者、他們之間的依賴方法。
觀察者模式的優點:
- 觀察者和被觀察者是抽象耦合的
- 建立了一套觸發機制。
Android中的使用:
我個人覺得觀察者模式可能android中應用最爲廣泛的一種設計模式了。別的不說,就按鈕的點擊事件onClick而言,就可以看做爲一種觀察者模式,這個過程中Button其實可以被看做是被觀察者,onClick事件可以看做是觀察者,而setOnClickListener方法就是它們之間的添加依賴關係的方法。當Button狀態發生改變時,即被點擊後,則通知了onClick完成更新。
另外大家所熟知的Rxjava其核心思想也是一種觀察者模式,最爲直觀地就是其五大基類之一的Observable,Observable通過subscribe方法去訂閱Observer來完成。通過命名我們也能知道,Observable是被觀察者,Observer是觀察者,而subscribe方法則是它們之間的依賴方法。(需要注意的是Rxjava中的觀察者模式觀察者與被觀察者的依賴關係是反着的,一般情況下應該是觀察者去subscribe被觀察者,這裏則是被觀察者去訂閱觀察者)。
接下來我們以一個簡單的例子來說明觀察者模式的簡單代碼實現,這個例子就是開頭所提到的警察抓捕小偷的過程。第一步:我們需要創建一個Observer的抽象類,用來抽象觀察者方法。
//被觀察者的抽象方法
public abstract class Observer {
//當被觀察者狀態改變時,所有觀察者更新方法
public abstract void update(boolean b);
}
第二步:創建被觀察者對象,即是例子裏的犯罪分子,並且定義一個集合observers用來存放所有的觀察者對象,定義一個布爾型的isCrime來保存被觀察者的狀態,即犯罪分子是否實施犯罪。
/**
* 被觀察者對象 -- 犯罪分子
*/
public class Offender {
//定義集合 存放所有觀察者對象
private List<Observer> observers = new ArrayList<>();
private boolean isCrime;
public boolean isCrime() {
return isCrime;
}
public void setCrime(boolean crime) {
isCrime = crime;
notifyAllObservers();
}
//訂閱方法 -- 添加與觀察者的依賴關係
public void subscribe(Observer observer){
observers.add(observer);
}
//通知所有觀察者更新
public void notifyAllObservers(){
for (Observer observer:observers) {
observer.update(isCrime());
}
}
}
第三步:創建多個繼承自Observer的觀察者類並實現其update方法。
//觀察者 -- A警察
public class PuliceA extends Observer {
@Override
public void update(boolean b) {
if (b){
Log.i("ledding", "PuliceA 開始抓捕");
}else{
Log.i("ledding", "PuliceA 繼續觀察");
}
}
}
//觀察者 -- B警察
public class PuliceB extends Observer {
@Override
public void update(boolean b) {
if (b){
Log.i("ledding", "PuliceB 開始抓捕");
}else{
Log.i("ledding", "PuliceB 繼續觀察");
}
}
}
第四步:代碼中實現使用。
//創建被觀察者-犯罪分子
Offender offender = new Offender();
//添加依賴關係
offender.subscribe(new PuliceA());
offender.subscribe(new PuliceB());
//還沒有實施犯罪
offender.setCrime(false);
//實施犯罪
offender.setCrime(true);
最後來看下打印的日誌是否實現了我們的預期。