前言
我們在Android ListView或者Recyclerview的開發中,常常是資料更新之後要立刻去更新界面,這種Adapter的notifyDateSetChanged就運用了觀察者模式;觀察者模式是一種使用率非常高的模式,常常用到GUI之類的的系統中,界面跟随資料發生改變,使得UI和具體的頁面邏輯分開解耦,換而言之,觀察者模式就是一對多的關系,一個對象發生改變,其依賴于它的所有對象都收到通知,更新對象本身。
适用場景
1,事件多級觸發場景,一對多關系的一種展現。
2,事件總線場景,這個最多使用的是EventBus。
角色扮演
Subject:被觀察者的抽象類,一般提供接口滿足添加和删除觀察者對象。
ConcreteSubject:具體的被觀察者,實作Subject的接口。
Observer:抽象觀察者,就是觀察者的抽象類,定義更新接口來更新自己的資料。
ConcreteObserver:具體觀察者,實作更新自身資料的方法。
觀察者模式的簡單實作
簡單抽象一個demo,我的桌子上有一個電子溫度計,其功能就是顯示室内溫度跟濕度,那麼我們抽象的過程就是,當溫控原件檢測到溫度和濕度發生變化時,通知界面重新整理,首先我們申明抽象被觀察者:
package com.demo.observable;
/**
* Created by italkbb on 2017/12/25.
*/
/**
* 被觀察者的接口
*/
public interface Subject {
/**
* 注冊觀察者
*/
void registerObserver(Observer observer);
/**
* 移除觀察者
*/
void deleteObservers();
/**
* 通知觀察者
*/
void notifyObservers();
}
下面實作這個被觀察者:
package com.demo.observable;
import java.util.ArrayList;
import java.util.List;
/**
* Created by italkbb on 2017/12/25.
*/
public class WeatherSubject implements Subject {
// 觀察者
private List<Observer> mObservers;
// 資訊
private float mTemperature;//溫度
private float mHumidity;//濕度
public WeatherSubject(){
this.mObservers = new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer observer) {
this.mObservers.add(observer);
}
@Override
public void deleteObservers() {
this.mObservers.clear();
}
@Override
public void notifyObservers() {
for (Observer observer : mObservers) {
observer.updateInfo();
}
}
public void setWeatherInfo(float temperature, float humidity) {
this.mTemperature = temperature;
this.mHumidity = humidity;
// 資訊更新完畢了,通知觀察者
notifyObservers();
}
/**
* 得到測量溫度
* @return
*/
public float getTemperature() {
return mTemperature;
}
/**
* 得到測量濕度
* @return
*/
public float getHumidity() {
return mHumidity;
}
}
上面的類基本滿足了裝置資訊改變通知觀察者的功能,下面同樣來寫觀察者:
package com.demo.observable;
/**
* Created by italkbb on 2017/12/25.
*/
/**
* 觀察者接口
*/
public interface Observer {
void updateInfo();
}
實作它:
package com.demo.observable;
/**
* Created by italkbb on 2017/12/25.
*/
public class WeatherInfoDisplay implements Observer {
private WeatherSubject mWeatherSubject;
private float mTemperature;//溫度
private float mHumidity;//濕度
public WeatherInfoDisplay(WeatherSubject weatherSubject){
this.mWeatherSubject = weatherSubject;
this.mWeatherSubject.registerObserver(this);
}
public void display() {
// 簡單抽象顯示為java的列印語句
System.out.println("溫度:" + this.mTemperature + "℃");
System.out.println("濕度:" + this.mHumidity);
}
@Override
public void updateInfo() {
this.mTemperature = this.mWeatherSubject.getTemperature();
this.mHumidity = this.mWeatherSubject.getHumidity();
display();
}
}
接下來就簡單使用一下:
package com.demo.observable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import teltplay.example.com.kotlindemo.R;
public class WeatherActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_weather);
WeatherSubject mWeatherSubject = new WeatherSubject();
WeatherInfoDisplay mWeatherInfoDisplay = new WeatherInfoDisplay(mWeatherSubject);
mWeatherSubject.setWeatherInfo(f,f);
}
}
就這樣一個簡單的觀察者模式就完成了,當然要實作複雜的邏輯,也就大同小異了。
後記
優點缺點說一下,優點嘛,觀察者與被觀察者低耦合,也就增加了代碼的擴充性;缺點就是如果簡單的采取循環通知觀察者,可能會由于順序執行的關系卡住線程,但這個用多線程就會解決,但同時帶來的就是效率問題了,太多的觀察者,在多線程,資源消耗值得考慮。