在讲观察者模式之前,我们还是用一个案例来说明一下。
小明的上司又有新任务给他了,让他做一个和Internet气象站合作的项目。项目所需要的数据类是气象站提供的,小明公司主要任务是提供温度、气压和湿度的接口,测量数据更新时需时时通知给第三方,需要设计开放型API便于其他第三方公司也能接入气象站获取数据。
小明一开始是用普通的OO思想去做的。
首先,气象站提供了WeatherData类:
然后小明根据这个设计了整体的设计方案,CurrentConditions为数据公告板,用来显示数据:
设计代码:
气象站提供的WeatherData类:
public class WeatherData {
private float mTemperatrue;//温度
private float mPressure;//气压
private float mHumidity;//湿度
private CurrentConditions currentConditions;//显示器
public WeatherData(CurrentConditions currentConditions){
this.currentConditions=currentConditions;
}
public float getmTemperatrue() {
return mTemperatrue;
}
public float getmPressure() {
return mPressure;
}
public float getmHumidity() {
return mHumidity;
}
public void dataChange(){
currentConditions.update(getmTemperatrue(), getmPressure(), getmHumidity());;
}
public void setData(float mTemperatrue,float mPressure,float mHumidity){
this.mTemperatrue=mTemperatrue;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
dataChange();
}
}
小明开发些的显示板CurrentConditions类:
public class CurrentConditions {
private float mTemperatrue;//温度
private float mPressure;//气压
private float mHumidity;//湿度
public void update(float mTemperatrue,float mPressure,float mHumidity){
this.mTemperatrue=mTemperatrue;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
display();
}
public void display(){
System.out.println("今天的温度是"+mTemperatrue);
System.out.println("今天的气压是"+mPressure);
System.out.println("今天的湿度是"+mHumidity);
}
}
测试类Test:
public class Test {
public static void main(String[] args) {
CurrentConditions currentConditions;
WeatherData weatherData;
currentConditions=new CurrentConditions();
weatherData=new WeatherData(currentConditions);
weatherData.setData(30, 150, 20);
}
}
这样总体的功能就出来了,但是这样的话,当第三方接入的话就不好维护了,在dataChange()方法里面肯定要加入第三方的公告板的更新函数,所以就必须在WeatherData构造方法里面添加参数或者再添加一个函数,每增加一个公司
就必须在dataChange()方法添加一部分代码,这样会导致每次有WeatherData接口函数要重新编译一遍,无法动态的添加第三方。
对于这个问题,小明对项目进行改进,方案如下:
先把公告板抽离出来,写一个Observer接口类:
public interface Observer {
public void update(float mTemperatrue,float mPressure,float mHumidity);
}
今天的公告板CurrentCondition类:
public class CurrentCondition implements Observer {
private float mTemperatrue;//温度
private float mPressure;//气压
private float mHumidity;//湿度
public void update(float mTemperatrue,float mPressure,float mHumidity){
this.mTemperatrue=mTemperatrue;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
display();
}
public void display(){
System.out.println("今天的温度是"+mTemperatrue);
System.out.println("今天的气压是"+mPressure);
System.out.println("今天的湿度是"+mHumidity);
}
}
明天的公告板NextCondition类:
public class NextCondition implements Observer {
private float mTemperatrue;//温度
private float mPressure;//气压
private float mHumidity;//湿度
public void update(float mTemperatrue,float mPressure,float mHumidity){
this.mTemperatrue=mTemperatrue;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
display();
}
public void display(){
System.out.println("明天的温度是"+mTemperatrue);
System.out.println("明天的气压是"+mPressure);
System.out.println("明天的湿度是"+mHumidity);
}
}
对于数据类,我们给他注册,移除,和通知,为了更合理的完善项目,写一个Subject接口类:
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
然后数据类实现Subject类的WeatherData类:
public class WeatherData implements Subject {
private float mTemperatrue;//温度
private float mPressure;//气压
private float mHumidity;//湿度
private ArrayList<Observer> observers;
public WeatherData() {
observers = new ArrayList<Observer>();
}
public float getmTemperatrue() {
return mTemperatrue;
}
public float getmPressure() {
return mPressure;
}
public float getmHumidity() {
return mHumidity;
}
public void dataChange(){
notifyObserver();
}
public void setData(float mTemperatrue,float mPressure,float mHumidity){
this.mTemperatrue=mTemperatrue;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
dataChange();
}
public void registerObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
if(observers.contains(o)){
observers.remove(o);
}
}
public void notifyObserver() {
for(int i=0;i<observers.size();i++){
observers.get(i).update(getmTemperatrue(), getmPressure(), getmHumidity());
}
}
}
这样就可以实现灵活的添加第三方公司,使项目的拓展性得以体现。
测试类Test:
public class Test {
public static void main(String[] args) {
CurrentCondition currentConditions=new CurrentCondition();
NextCondition nextCondition=new NextCondition();
WeatherData weatherData=new WeatherData();
weatherData.registerObserver(currentConditions);
weatherData.registerObserver(nextCondition);
weatherData.setData(111, 222, 333);
weatherData.removeObserver(currentConditions);
weatherData.setData(333, 555, 666);
}
}
当然,还可以用java内置观察者,它的作用和观察者方法一样,它本身提供了注册,移除,通知功能,Observable(这是个类,而不是接口,所以只能继承,而不能实现)和Observer(这是个接口)是java内置观察者提供的,下面用java内置观察者来实现上面的功能:
WeahterData 类:
public class WeahterData extends Observable {
private float mTemperatrue;//温度
private float mPressure;//气压
private float mHumidity;//湿度
public float getmTemperatrue() {
return mTemperatrue;
}
public float getmPressure() {
return mPressure;
}
public float getmHumidity() {
return mHumidity;
}
public void dataChange(){
this.setChanged();
this.notifyObservers(new Data(getmTemperatrue(),getmPressure(),getmHumidity()));
}
public void setData(float mTemperatrue,float mPressure,float mHumidity){
this.mTemperatrue=mTemperatrue;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
dataChange();
}
//这里提供一个数据类
public class Data{
float mTemperatrue;//温度
float mPressure;//气压
float mHumidity;//湿度
public Data(float mTemperatrue,float mPressure,float mHumidity){
this.mTemperatrue=mTemperatrue;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
}
}
}
CurrentCondition 类:
public class CurrentCondition implements Observer {
private float mTemperatrue;//温度
private float mPressure;//气压
private float mHumidity;//湿度
public void update(Observable arg, Object arg1) {
this.mTemperatrue=((Data)arg1).mTemperatrue;
this.mPressure=((Data)arg1).mPressure;
this.mHumidity=((Data)arg1).mHumidity;
display();
}
public void display(){
System.out.println("今天的温度是"+mTemperatrue);
System.out.println("今天的气压是"+mPressure);
System.out.println("今天的湿度是"+mHumidity);
}
}
NextCondition 类:
public class NextCondition implements Observer {
private float mTemperatrue;//温度
private float mPressure;//气压
private float mHumidity;//湿度
public void update(Observable arg, Object arg1) {
this.mTemperatrue=((Data)arg1).mTemperatrue;
this.mPressure=((Data)arg1).mPressure;
this.mHumidity=((Data)arg1).mHumidity;
display();
}
public void display(){
System.out.println("明天的温度是"+mTemperatrue);
System.out.println("明天的气压是"+mPressure);
System.out.println("明天的湿度是"+mHumidity);
}
}
测试类Test:
public class Test {
public static void main(String[] args) {
CurrentCondition currentConditions=new CurrentCondition();
NextCondition nextCondition=new NextCondition();
WeahterData weatherData=new WeahterData();
weatherData.addObserver(currentConditions);
weatherData.addObserver(nextCondition);
weatherData.setData(39, 123, 45);
weatherData.deleteObserver(currentConditions);
weatherData.setData(40, 213, 50);
}
}
总结:
观察者模式:对象之间多对一依赖的一种设计方案,以便一个对象的状态发送变化时,所有依赖于它的对象都得到通知并自动刷新。就相当于气象站给出的数据变化时,每个显示板的数据也会跟着刷新。