前言:最近一个朋友和我说,当生活变得不顺的时候,她发现坚持太多所谓的原则和底线其实并没有太多的意义,生活最大的意义就是做自己该做的事,喜欢做的事。我也鼓励一个朋友,趁年轻赶紧去想办法搞事情,让一些独一无二的经历使自己变得和别人看起来有那么一丝的不同。
勿问成功的秘诀为何,且尽全力做你应该做的事吧。——美华纳
观察者模式是一个很好将观察者和被观察者解耦的模式,观察者只需要在被观察者中进行注册,告诉被观察者,当你内部数据改变的时候对我进行提醒。
还记得当初刚开始学Android的时候,听说了一个概念叫做回调函数,一直对其不解。现在学习观察者模式,就有一种恍然大悟的感觉,因为观察者模式中就是用了回调函数。
接下来让我们来介绍下我们帅气的观察者模式吧,让我用Head first 设计模式中的一个例子进行举例吧。
比如我们现在有一个观察温度的电子板,它会在温度进行改变的时候获取到改变的温度数值,并显示在温度电子版上。
观察者模式中需要几个类,我们来看看:
抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。主题和被观察者是一个概念,在下文中我将使用主题这个词来代替被观察者这个词。
抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
首先,我们来写一个抽象的主题:
<span style="font-family:Microsoft YaHei;font-size:18px;">package com.example.observerpattern;
/**
* Created by Vicky on 2016/10/28.
*/
//抽象的主题
public interface Subject {
//观察者可以通过这个方法进行注册
public void registerObserver(Observer observer);
//观察者可以通过这个方法进行解除注册
public void removeObserver(Observer observer);
//这个方法用来通知所有的观察者对象
public void notifyObserver();
}
</span>
其中你可能会问,这个Observer是什么,这个就是我们的抽象的观察者接口:
<span style="font-family:Microsoft YaHei;font-size:18px;">package com.example.observerpattern;
/**
* Created by Vicky on 2016/10/28.
*/
public interface Observer {
//抽象观察者
public void update(float temperature);
}
</span>
有了抽象的观察者和主题,我们就可以实现他们的具体类了。首先我们来实现主题的具体类:
<span style="font-family:Microsoft YaHei;font-size:18px;">package com.example.observerpattern;
import java.util.ArrayList;
import java.util.Iterator;
/**
* Created by Vicky on 2016/10/28.
*/
public class WeatherData implements Subject{
//用来存放所有的观察者对象
private ArrayList<Observer> observerArrayList;
private float temperature=0;
public WeatherData(){
observerArrayList=new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
//观察者通过调用这个方法进行注册
observerArrayList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
//观察者通过调用这个方法解除注册
int index=observerArrayList.indexOf(observer);
observerArrayList.remove(index);
}
@Override
public void notifyObserver() {
//通过调用这个方法,通知所有的观察者对象
Iterator<Observer> iterator=observerArrayList.iterator();
if (iterator.hasNext()){
Observer observer=iterator.next();
observer.update(temperature);
}
}
public void setMeasurement(float temperature){
//当我们的气温改变的时候,调用notifyObserver()方法,通知所有观察者气温改变了
if (this.temperature-temperature!=0){
this.temperature=temperature;
notifyObserver();
}
}
}
</span>
我们定义了WeatherData类实现了抽象的主题接口,实现了registerObserver(),removeObserver(),notifyObserver()方法,供监听者进行注册、解除注册和通知监听者。
接下来我们来看一下我们的监听者具体的实现类:
<span style="font-family:Microsoft YaHei;font-size:18px;">package com.example.observerpattern;
import android.util.Log;
/**
* Created by Vicky on 2016/10/28.
*/
public class CurrentConditionDisplay implements Observer{
private Subject weatherData;
private float temperature;
public CurrentConditionDisplay(Subject weatherData){
this.weatherData=weatherData;
//注册监听,把自己传给主题,其实这里就是运用了回调的知识,当主题的数据改变的时候,主题可以通过传的这个对象进行调用Updata()方法。
weatherData.registerObserver(this);
}
@Override
public void update(float temperature) {
this.temperature=temperature;
Log.d("WeatherData","temperature:"+temperature);
}
}
</span>
最后我们通过以下代码进行测试一下我们所写的监听者模式是否正常工作了:
<span style="font-family:Microsoft YaHei;font-size:18px;">WeatherData weatherData=new WeatherData();
CurrentConditionDisplay currentConditionDisplay=new CurrentConditionDisplay(weatherData);
weatherData.setMeasurement(80);
weatherData.setMeasurement(77);</span>
打印的内容如下:
10-28 15:33:40.226 29652-29652/com.example.observerpattern D/WeatherData: temperature:80.0
10-28 15:33:40.226 29652-29652/com.example.observerpattern D/WeatherData: temperature:77.0
说明我们的代码正常工作了,当温度改变的时候,我们会通知监听者进行打印改变后的数据。
监听者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖着都会收到通知并自动更新。