參考文檔:
http://www.lxweimin.com/p/d55ee6e83d66
文章中的例子來源于參考文獻(xiàn),更詳細(xì)的講解在參考文章中,本文是自己的一個理解
觀察者模式使用場景:
A對象(觀察者)對B對象(被觀察者)的某種變化高度敏感,需要在B變化的一瞬間做出反應(yīng)。在代碼上實現(xiàn)上,通常是被觀察者主動去注冊或者訂閱一個觀察者,
構(gòu)建觀察者模式
1.被觀察者持有觀察者對象,這一步驟通常是通過被觀察者注冊(Register方法)或者訂閱(Subscribe方法)觀察者實現(xiàn)的。
2.觀察者同樣持有被觀察者對象,同時調(diào)用被觀察者的訂閱方法完成訂閱。(被觀察者拿到觀察者對象這一步通常在觀察者類中去做。)
3.被觀察者具有一個"通知觀察者的"方法,該方法通過調(diào)用被觀察者內(nèi)部持有的觀察者對象的方法來達(dá)到通知觀察者的目的。
(其實所謂收到通知就是被觀察者做某些操作時,同時調(diào)用了觀察者的特定方法。)
實現(xiàn)過程
被觀察者接口
/** * 主題(發(fā)布者、被觀察者) */
public interface Subject {
/** * 注冊觀察者 */
void registerObserver(Observer observer);
/** * 移除觀察者 */
void removeObserver(Observer observer);
/** * 通知觀察者 */
void notifyObservers(); }
觀察者接口
/** * 觀察者 */
public interface Observer {
void update();
}
具體實現(xiàn)
被觀察者:
1.被觀察者持有觀察者對象。
2.被觀察者持有的觀察者對象通過訂閱(注冊方法拿到)
3.被觀察者數(shù)據(jù)改變的時候通知觀察者(通過調(diào)用觀察者的update方法)
public class WeatherData implements Subject {
private List<Observer> observers;//1.被觀察者持有觀察者對象。
private float temperature;
private float humidity;
private float pressure;
private List<Float> forecastTemperatures;
//未來幾天的溫度
public WeatherData() { this.observers = new ArrayList<Observer>();
//被觀察者持有的觀察者對象通過訂閱
@Override
public void registerObserver(Observer observer) { this.observers.add(observer); }
@Override
public void removeObserver(Observer observer) {
this.observers.remove(observer);
}
通知觀察者
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
在數(shù)據(jù)更新的時候通知觀察者
public void changeWeatherData(float temperature, float humidity, float pressure, List<Float> forecastTemperatures) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
this.forecastTemperatures = forecastTemperatures;
notifyObservers();
}
public float getTemperature() { return temperature; }
public float getHumidity() { return humidity; }
public float getPressure() { return pressure; }
public List<Float> getForecastTemperatures() { return forecastTemperatures; }}
觀察者:
1.觀察者持有被觀察者對象(WeatherData)
2.將自身傳遞給被觀察者(使用被觀察者的注冊方法)
3.提供一個方法,負(fù)責(zé)在被觀察者改變的時候刷新自身。(持有update方法,update方法實際做事情,該方法在被觀察者中被調(diào)用)
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private WeatherData weatherData; //持有被觀察者對象
private float temperature;
private float humidity;
private float pressure;
public CurrentConditionsDisplay(WeatherData weatherData) {
this.weatherData = weatherData;
this.weatherData.registerObserver(this);//被觀察者對象拿到觀察者
}
@Override
public void display() {
System.out.println("當(dāng)前溫度為:" + this.temperature + "℃");
System.out.println("當(dāng)前濕度為:" + this.humidity);
System.out.println("當(dāng)前氣壓為:" + this.pressure); }
@Override
public void update() {
//數(shù)據(jù)都是通過被觀察者拿到的
this.temperature = this.weatherData.getTemperature();
this.humidity = this.weatherData.getHumidity();
this.pressure = this.weatherData.getPressure();
display();
}
}
使用例子:
//被觀察者
WeatherData weatherData = new WeatherData();
//觀察者
CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
//被觀察者數(shù)據(jù)改變
List<Float> forecastTemperatures = new ArrayList<Float>();
forecastTemperatures.add(22f);
forecastTemperatures.add(-1f);
forecastTemperatures.add(9f);
weatherData.changeWeatherData(22f, 0.8f, 1.2f, forecastTemperatures);
//被觀察者數(shù)據(jù)改變的時候(即調(diào)用changeWeatherData時,實際上內(nèi)部調(diào)用了觀察者的update方法,主動通知觀察者)
筆者使用實例:
場景:在RecycleView中需要一個測試每一個展示出來的ip的延時,并且展示在Recycleview上。延時的展示和其他數(shù)據(jù)的展示是不同步的。測量延時采用的策略是 ping 地址5秒后拿到一個結(jié)果。所以采用觀察者模式,當(dāng)獲取到延時數(shù)據(jù)(即數(shù)據(jù)改變的時候)更新UI。
被觀察者RobotBean對象
1.持有觀察者對象:registerOberver方法
2.被觀察者改變的時候通知觀察者:notifyIpChange方法
觀察者ViewHolder對象
1.持有被觀察對象
2.傳遞觀察者:
3.提供一個更新方法