第二式 观察者模式

观察者模式

一 气象站应用项目

  这天公司接到一个气象站项目,气象站通过自己的各类检测器获得的数据打包提供给我们,我们来帮他们实现在不同的布告板上展示,可以显示目前状况,气象统计及简单预报。并且还希望我们能公布一组API,好让其他的开发者写出自己的布告板。

  项目概况:我们建立一个应用,利用WeatherData对象取得数据,并更新三个布告板:目前情况、气象统计和天气预报。

  

二 认识观察者模式

  在开始着手上面的项目前,我们来认识一下观察者模式。相信大家都有过订阅报纸或者订牛奶的经历,我们来看看是怎么个过程。

  首先,报社的任务是出版报纸,用户向报社订阅报纸,只要他们有新报纸出版就会送给你,如果你不想看了,取消订阅,他们就不会再送了;只要报社还没破产倒闭就一直存在订阅和取消订阅的行为。

  出版者 + 订阅者 = 观察者模式。观察者模式中出版者称作主题,订阅者称作观察者

  观察者模式:定义了对象之间的一对多依赖,这样一来,一个对象改变状态时,他的所有依赖者都会收到通知并自动更新。

  UML图如下:

   

  设计原则:为了交互对象之间的松耦合设计而努力。

  观察者模式提供了一种对象设计,让主题和观察者之间松耦合。关于观察者的一切,主题只知道他实现了观察者接口,主题不知道他具体是谁,做了哪些细节上的事。

  我们可以在任何时候增加新的观察者,而不需要修改主题的代码;同样也可以删掉旧的观察者。我们可以在其他地方独立的复用主题或观察者,因为他们之间并非紧耦合。

  松耦合的设计之所以能让我们建立弹性的OO系统,能够应对变化,是因为对象之间的相互依赖降到了最低。

三 气象站代码实现

  UML类图:

  

  代码:

  1.创建主题、观察者、布告展示接口;天气数据封装到Data类

public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
public interface Observer {
public void update(Data data);
}

public interface DisplayElement {
public void display();
}
public class Data {
private float temp;
private float humidity;
private float pressure;

public Data(float temp, float humidity, float pressure) {
this.temp = temp;
this.humidity = humidity;
this.pressure = pressure;
}

@Override
public String toString() {
return "Data{" +
"temp=" + temp +
", humidity=" + humidity +
", pressure=" + pressure +
'}';
}

public float getTemp() {
return temp;
}

public void setTemp(float temp) {
this.temp = temp;
}

public float getHumidity() {
return humidity;
}

public void setHumidity(float humidity) {
this.humidity = humidity;
}

public float getPressure() {
return pressure;
}

public void setPressure(float pressure) {
this.pressure = pressure;
}
}

  

  2.实现主题接口的天气数据主题类

public class WeatherData implements Subject{
private List<Observer> list;
private Data data;

public WeatherData(){
list = new ArrayList<Observer>();
}

public void registerObserver(Observer o) {
//注册观察者时,将观察者添加到list中
list.add(o);
}

public void removeObserver(Observer o) {
//观察者取消订阅时
list.remove(o);
}

public void notifyObservers() {
//通知所有已注册观察者
for(Observer o : list){
o.update(data);
}
}

public void dataChanged(){
//气象站数据变更后,通知观察者
this.notifyObservers();
}

public void setData(Data data){
this.data = data;
dataChanged();
}
}

   3.两种布告板观察者

public class CurrentConditionDisplay implements Observer,DisplayElement {
private Subject weatherData;
private Data data;

public CurrentConditionDisplay(Subject weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void display() {
System.out.println("CurrentConditionDisplay:"+this.data);
}

public void update(Data data) {
this.data = data;
display();
}
}
public class StaticsDisplay implements Observer,DisplayElement {
private Subject weatherData;
private Data data;

public StaticsDisplay(Subject weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void display() {
System.out.println("StaticsDisplay:"+this.data);
}

public void update(Data data) {
this.data = data;
display();
}
}
  4.测试类
public class Test {
public static void main(String[] args){
WeatherData weatherData = new WeatherData();
CurrentConditionDisplay display1 = new CurrentConditionDisplay(weatherData);
StaticsDisplay display2 = new StaticsDisplay(weatherData);
weatherData.setData(new Data(12,22,33.1f));
weatherData.setData(new Data(2.3f,42,13));
}
}
  5.测试结果如下

  

 四 Java内置的观察者模式

  现在,都是主题数据有更新时,一股脑把所有数据都传给观察者了,观察者可能不需要这么多数据,他可能想自己来拉取数据。我们来看看java内置的观察者模式。

  Java内置的观察者模式运作方式,和我们在气象站中的实现类似,但有一些小差异。最明显的差异是WeatherData现在扩展自Observable类,并继承到一些增加,删除,

  通知观察者的方法。Observable类中,有一个setChanged方法,及changed标志,通过这些可以让主题更灵活的选择是否向观察者发送数据。







猜你喜欢

转载自www.cnblogs.com/bwyhhx2018/p/10658285.html