標籤:string 模式 sys main notify gis listen over 內容
先看下這個模式的定義。
定義對象間的一種一對多的依賴關係,當一個對象的狀態發送改變時,所有依賴於它的對象都能得到通知並被自動更新
先來講幾個情景。
觀察上面兩個情景,有一個共同點,就是我們無需每時每刻關注我們感興趣的東西,我們只需做的就是訂閱感興趣的事物,比如天氣預報服務,雜誌等,一旦我們訂閱的事物發生變化,比如有新的天氣預報資訊,新的雜誌等,被訂閱的事物就會即時通知到訂閱者,即我們。而這些被訂閱的事物可以擁有多個訂閱者,也就是一對多的關係。當然,嚴格意義上講,這個一對多可以包含一對一,因為一對一是一對多的特例,沒有特殊說明,本文的一對多包含了一對一。
現在你反過頭來看看觀察者模式的定義,你是不是豁然開朗了。
然後我們看一下觀察者模式的幾個重要組成。
至於觀察者模式的具體實現,這裡帶帶大家實現一下情境一,其實java中提供了Observable類和Observer介面供我們快速的實現該模式,但是為了加深印象,我們不使用這兩個類。
情境1中我們感興趣的事情是天氣預報,於是,我們應該定義一個Weather實體類。
public class Weather { private String description; public Weather(String description) { this.description = description; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Override public String toString() { return "Weather{" + "description=‘" + description + ‘\‘‘ + ‘}‘; }}
然後定義我們的被觀察者,我們想要這個被觀察者能夠通用,將其定義成泛型。內部應該暴露register和unregister方法供觀察者訂閱和取消訂閱,至於觀察者的儲存,直接用ArrayList即可,此外,當有主題內容發送改變時,會即時通知觀察者做出反應,因此應該暴露一個notifyObservers方法,以上方法的具體實現見如下代碼。
public class Observable<T> { List<Observer<T>> mObservers = new ArrayList<Observer<T>>(); public void register(Observer<T> observer) { if (observer == null) { throw new NullPointerException("observer == null"); } synchronized (this) { if (!mObservers.contains(observer)) mObservers.add(observer); } } public synchronized void unregister(Observer<T> observer) { mObservers.remove(observer); } public void notifyObservers(T data) { for (Observer<T> observer : mObservers) { observer.onUpdate(this, data); } }}
而我們的觀察者,只需要實現一個觀察者的介面Observer,該介面也是泛型的。其定義如下。
public interface Observer<T> { void onUpdate(Observable<T> observable,T data);}
一旦訂閱的主題發送變換就會回調該介面。
我們來使用一下,我們定義了一個天氣變換的主題,也就是被觀察者,還有兩個觀察者觀察天氣變換,一旦變換了,就列印出天氣資訊,注意一定要調用被觀察者的register進行註冊,否則會收不到變換資訊。而一旦不敢興趣了,直接調用unregister方法進行取消註冊即可
public class Main { public static void main(String [] args){ Observable<Weather> observable=new Observable<Weather>(); Observer<Weather> observer1=new Observer<Weather>() { @Override public void onUpdate(Observable<Weather> observable, Weather data) { System.out.println("觀察者1:"+data.toString()); } }; Observer<Weather> observer2=new Observer<Weather>() { @Override public void onUpdate(Observable<Weather> observable, Weather data) { System.out.println("觀察者2:"+data.toString()); } }; observable.register(observer1); observable.register(observer2); Weather weather=new Weather("晴轉多雲"); observable.notifyObservers(weather); Weather weather1=new Weather("多雲轉陰"); observable.notifyObservers(weather1); observable.unregister(observer1); Weather weather2=new Weather("颱風"); observable.notifyObservers(weather2); }}
最後的輸出結果也是沒有什麼問題的,如下
觀察者1:Weather{description=’晴轉多雲’}觀察者2:Weather{description=’晴轉多雲’}觀察者1:Weather{description=’多雲轉陰’}觀察者2:Weather{description=’多雲轉陰’}觀察者2:Weather{description=’颱風’}
接下來我們看看觀察者模式在android中的應用。我們從最簡單的開始。還記得我們為一個Button設定點擊事件的代碼嗎。
Button btn=new Button(this);btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e("TAG","click"); }});
其實嚴格意義上講,這個最多算是回調,但是我們可以將其看成是一對一的觀察者模式,即只有一個觀察者。
其實只要是set系列的設定監聽器的方法最多都只能算回調,但是有一些監聽器式add進去的,這種就是觀察者模式了,比如RecyclerView中的addOnScrollListener方法
private List<OnScrollListener> mScrollListeners;public void addOnScrollListener(OnScrollListener listener) { if (mScrollListeners == null) { mScrollListeners = new ArrayList<OnScrollListener>(); } mScrollListeners.add(listener);}public void removeOnScrollListener(OnScrollListener listener) { if (mScrollListeners != null) { mScrollListeners.remove(listener); }}public void clearOnScrollListeners() { if (mScrollListeners != null) { mScrollListeners.clear(); }}
類似的方法很多很多,都是add監聽器系列的方法,這裡也不再舉例。
還有一個地方就是Android的廣播機制,其本質也是觀察者模式,這裡為了簡單方便,直接拿本地廣播的代碼說明,即LocalBroadcastManager。
我們平時使用本地廣播主要就是下面四個方法
LocalBroadcastManager localBroadcastManager=LocalBroadcastManager.getInstance(this);localBroadcastManager.registerReceiver(BroadcastReceiver receiver, IntentFilter filter);localBroadcastManager.unregisterReceiver(BroadcastReceiver receiver);localBroadcastManager.sendBroadcast(Intent intent)
調用registerReceiver方法註冊廣播,調用unregisterReceiver方法取消註冊,之後直接使用sendBroadcast發送廣播,發送廣播之後,註冊的廣播會收到對應的廣播資訊,這就是典型的觀察者模式。
接下來我們看一下一些開源架構中的觀察者模式。一說到開源架構,你首先想到的應該是EventBus。沒錯,EventBus也是基於觀察者模式的。
觀察者模式的三個典型方法它都具有,即註冊,取消註冊,發送事件
EventBus.getDefault().register(Object subscriber);EventBus.getDefault().unregister(Object subscriber);EventBus.getDefault().post(Object event);
總之,在Android中觀察者模式還是被用得很頻繁的。
Android開發中常見的設計模式(三)——觀察者模式