觀察者模式
一侧纯、簡介
觀察者模式(又被稱為發(fā)布-訂閱(Publish/Subscribe)模式,屬于行為型模式的一種,它定義了一種一對多的依賴關(guān)系依鸥,讓多個(gè)觀察者對象同時(shí)監(jiān)聽某一個(gè)主題對象。這個(gè)主題對象在狀態(tài)變化時(shí)悼沈,會通知所有的觀察者對象贱迟,使他們能夠自動更新自己。該模式一個(gè)重要作用就是解耦絮供,將被觀察者和觀察者進(jìn)行解耦衣吠,使他們之間的依賴性更小
二、使用場景
- 關(guān)聯(lián)行為場景壤靶,需要注意的是關(guān)聯(lián)行為是可拆分的而不是“組合”關(guān)系
- 事件多級觸發(fā)場景
- 跨系統(tǒng)的消息交換場景缚俏,如消息隊(duì)列、事件總線的處理機(jī)制
三贮乳、簡單實(shí)現(xiàn)
這里我們以微信公眾號的訂閱為例忧换。公眾號當(dāng)其更新內(nèi)容時(shí)就會推送給訂閱了該公眾號的讀者。
//被觀察者
public class Wechat extends Observable{
public void postNewPublication(String content){
setChanged();
notifyObservers(content);
}
}
//觀察者
public class Reader implements Observer{
public String name ;
public Reader(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
Log.i(TAG, "update: wechat is update content is :"+arg);
}
}
public void test(){
Wechat wechat=new Wechat();
Reader reader1=new Reader("reader1");
Reader reader2=new Reader("reader2");
Reader reader3=new Reader("reader3");
wechat.addObserver(reader1);
wechat.addObserver(reader2);
wechat.addObserver(reader3);
wechat.postNewPublication("up up up");
}
這里需要注意的是Observer和Observable是JDK內(nèi)置的類向拆,表示觀察者和被觀察者亚茬。
四、觀察者模式在Android中應(yīng)用
ListView和RecycleView 的notifyDataSetChanged
當(dāng)我們在使用ListView或RecycleView時(shí)如果數(shù)據(jù)發(fā)生變化我們會調(diào)用Adapter的notifyDataSetChanged()方法,如下所示
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
在方法內(nèi)部調(diào)用了mDataSetObservable.notifyChanged浓恳,這里的mDataSetObservable是一個(gè)DataSetObservable實(shí)例
private final DataSetObservable mDataSetObservable = new DataSetObservable();
而DataSetObservable繼承自O(shè)bservable刹缝,我們看下DataSetObservable的notifyChanged方法
public class DataSetObservable extends Observable<DataSetObserver> {
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
}
可以看到調(diào)用了DataSetObserver的onChanged方法,DataSetObserver是一個(gè)抽類這里mObservers.get(i)獲得的是其子類AdapterDataSetObserver.
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();
if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
&& mOldItemCount == 0 && mItemCount > 0) {
AdapterView.this.onRestoreInstanceState(mInstanceState);
mInstanceState = null;
} else {
rememberSyncState();
}
checkFocus();
//重新布局
requestLayout();
}
...
public void clearSavedState() {
mInstanceState = null;
}
}
可以看到在AdapterDataSetObserver的onChanged方法中調(diào)用了requestLayout來進(jìn)行重新布局。
BroadcastReceiver
在Android中廣播也是基于觀察者模式的
五颈将、小結(jié)
觀察者模式優(yōu)點(diǎn):
- 解耦觀察者與被觀察者梢夯,應(yīng)對業(yè)務(wù)變化
- 增強(qiáng)系統(tǒng)靈活性、可擴(kuò)展性
缺點(diǎn):
- 在使用時(shí)要考慮開發(fā)效率和運(yùn)行效率吆鹤,程序中包括一個(gè)被觀察者厨疙、多個(gè)觀察者、開發(fā)調(diào)試等內(nèi)容會比較復(fù)雜疑务,且Java中消息通知默認(rèn)是順序執(zhí)行沾凄,如果一個(gè)觀察者卡頓,那么會影響整體執(zhí)行效率知允,在這種情況下一般考慮使用異步的方式撒蟀。