二、观察者模式(observer-patterns)
1、引出观察者模式:
Internet 气象站项目,普通OO设计方案,有些问题:
提供温度、气压和湿度的接口,测量数据更新时需要将数据实时通知第三方。需要设计开放API 便于其他第三方公司也能接入气象站获取数据。
2、假设气象站提供了一个WeatherData类获取温度,湿度,气压。
气象站检测到的数据一旦发生改变WeatherData就调用dataChange()方法获取数据。
3、一个通常的设计方案。
在公告板中有update()和 display();
update() 就是外面有数据的话就给我,然后在display()中显示。
气象站调用dataChange()获取三个参数然后给公告板,公告板获取数据后展示。
代码如下:
package observer.extraction;
/*
* 获取从气象站提供的天气信息,包含温度、湿度、气压
*/
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.mPressure = mPressure;
this.mTemperatrue = mTemperatrue;
this.mHumidity = mHumidity;
dataChange();
}
}
package observer.extraction;
/*
* 公告板
*/
public class CurrentConditions {
private float mTemperatrue;
private float mPressure;
private float mHumidity;
public void update(float mTemperatrue,float mPressure,float mHumidity) {
this.mPressure = mPressure;
this.mTemperatrue = mTemperatrue;
this.mHumidity = mHumidity;
display();
}
public void display() {
System.out.println("****ToDay mTemperatrue"+mTemperatrue);
System.out.println("****ToDay mPressure"+mPressure);
System.out.println("****ToDay mHumidity"+mHumidity);
}
}
package observer.extraction;
public class InternetWeather {
public static void main(String[] args) {
CurrentConditions currentConditions = new CurrentConditions();
WeatherData WeatherData = new WeatherData(currentConditions);
WeatherData.setData(30,40,500);
}
}
但是如果说改变需求,如果另外一个公司要新加一个获取一周只能的天气情况的功能。
那么解决方法就是在Weather的 dataChange()方法中添加其他公告板
问题:
1)其他第三方公司接入气象站获取数据的问题。
2)无法在运行时动态的添加第三方。
这就导致了需要很多次编译运行,没有扩展性。
因为公告板有很多种,所以就要将其设计为接口+实现,那么同样的dataChange()由于公告板的变化,它也要设计为接口+实现。
观察者模式原理
1 观察者模式就像定牛奶业务。
1)奶站,Subject
2)用户,Observer
2 、Subject: 登记注册、移除和通知
3、Observer:接收输入
观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject 通过Observer变化
用观察者模式重新设计
package observer.produce;
public interface Observer {
public void update(float mTemperature,float mPressure,float mHumidity);
}
package observer.produce;
/*
* 公告板
*/
public class ForcastConditions implements Observer {
private float mTemperatrue;
private float mPressure;
private float mHumidity;
@Override
public void update(float mTemperatrue,float mPressure,float mHumidity) {
this.mPressure = mPressure;
this.mTemperatrue = mTemperatrue;
this.mHumidity = mHumidity;
display();
}
public void display() {
System.out.println("****ToDay mTemperatrue: "+mTemperatrue);
System.out.println("****ToDay mPressure: "+mPressure);
System.out.println("****ToDay mHumidity: "+mHumidity);
}
}
package observer.produce;
/*
* 公告板
*/
public class CurrentConditions implements Observer {
private float mTemperatrue;
private float mPressure;
private float mHumidity;
@Override
public void update(float mTemperatrue,float mPressure,float mHumidity) {
this.mPressure = mPressure;
this.mTemperatrue = mTemperatrue;
this.mHumidity = mHumidity;
display();
}
public void display() {
System.out.println("****ToDay mTemperatrue: "+mTemperatrue);
System.out.println("****ToDay mPressure: "+mPressure);
System.out.println("****ToDay mHumidity: "+mHumidity);
}
}
package observer.produce;
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
package observer.produce;
import java.util.ArrayList;
/*
* 获取从气象站提供的天气信息,包含温度、湿度、气压
*/
public class WeatherData implements Subject {
private float mTemperatrue;
private float mPressure;
private float mHumidity;
private ArrayList<Observer> Observers;
public WeatherData(CurrentConditions CurrentConditions) {
Observers = new ArrayList<Observer>();
}
public float getmTemperatrue() {
return mTemperatrue;
}
public float getmPressure() {
return mPressure;
}
public float getmHumidity() {
return mHumidity;
}
/**
* 气象站提供的数据传给公告板
*/
public void dataChange() {
notifyObservers();
}
/**
* 假设气象站传数据
*/
public void setData(float mTemperatrue,float mPressure,float mHumidity) {
this.mPressure = mPressure;
this.mTemperatrue = mTemperatrue;
this.mHumidity = mHumidity;
dataChange();
}
@Override
public void registerObserver(Observer o) {
Observers.add(o);
}
@Override
public void removeObserver(Observer o) {
if (Observers.contains(o)) {
Observers.remove(o);
}
}
@Override
public void notifyObservers() {
// TODO Auto-generated method stub
for (Observer observer : Observers) {
observer.update(getmTemperatrue(), getmPressure(), getmHumidity());
}
}
}
package observer.produce;
public class InternetWeather {
public static void main(String[] args) {
CurrentConditions currentConditions = new CurrentConditions();
ForcastConditions forcastConditions = new ForcastConditions();
WeatherData WeatherData = new WeatherData(currentConditions);
WeatherData.registerObserver(currentConditions);
WeatherData.registerObserver(forcastConditions);
WeatherData.setData(30,40,500);
System.out.println("-----------------------");
WeatherData.removeObserver(currentConditions);
WeatherData.setData(30,40,500);
}
}