zoukankan      html  css  js  c++  java
  • 第二式 观察者模式

    观察者模式

    一 气象站应用项目

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

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

      

    二 认识观察者模式

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

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

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

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

      UML图如下:

       

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

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

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

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

    三 气象站代码实现

      UML类图:

      

      代码:

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

     1 public interface Subject {
     2     public void registerObserver(Observer o);
     3     public void removeObserver(Observer o);
     4     public void notifyObservers();
     5 }
     6 public interface Observer {
     7     public void update(Data data);
     8 }
     9 
    10 public interface DisplayElement {
    11     public void display();
    12 }
    13 public class Data {
    14     private float temp;
    15     private float humidity;
    16     private float pressure;
    17 
    18     public Data(float temp, float humidity, float pressure) {
    19         this.temp = temp;
    20         this.humidity = humidity;
    21         this.pressure = pressure;
    22     }
    23 
    24     @Override
    25     public String toString() {
    26         return "Data{" +
    27                 "temp=" + temp +
    28                 ", humidity=" + humidity +
    29                 ", pressure=" + pressure +
    30                 '}';
    31     }
    32 
    33     public float getTemp() {
    34         return temp;
    35     }
    36 
    37     public void setTemp(float temp) {
    38         this.temp = temp;
    39     }
    40 
    41     public float getHumidity() {
    42         return humidity;
    43     }
    44 
    45     public void setHumidity(float humidity) {
    46         this.humidity = humidity;
    47     }
    48 
    49     public float getPressure() {
    50         return pressure;
    51     }
    52 
    53     public void setPressure(float pressure) {
    54         this.pressure = pressure;
    55     }
    56 }

      

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

     1 public class WeatherData implements Subject{
     2     private List<Observer> list;
     3     private Data data;
     4 
     5     public WeatherData(){
     6         list = new ArrayList<Observer>();
     7     }
     8 
     9     public void registerObserver(Observer o) {
    10         //注册观察者时,将观察者添加到list中
    11         list.add(o);
    12     }
    13 
    14     public void removeObserver(Observer o) {
    15         //观察者取消订阅时
    16         list.remove(o);
    17     }
    18 
    19     public void notifyObservers() {
    20         //通知所有已注册观察者
    21         for(Observer o : list){
    22             o.update(data);
    23         }
    24     }
    25 
    26     public void dataChanged(){
    27         //气象站数据变更后,通知观察者
    28         this.notifyObservers();
    29     }
    30 
    31     public void setData(Data data){
    32         this.data = data;
    33         dataChanged();
    34     }
    35 }

       3.两种布告板观察者

     1 public class CurrentConditionDisplay implements Observer,DisplayElement {
     2     private Subject weatherData;
     3     private Data data;
     4 
     5     public CurrentConditionDisplay(Subject weatherData){
     6         this.weatherData = weatherData;
     7         weatherData.registerObserver(this);
     8     }
     9     public void display() {
    10         System.out.println("CurrentConditionDisplay:"+this.data);
    11     }
    12 
    13     public void update(Data data) {
    14         this.data = data;
    15         display();
    16     }
    17 }
    18 public class StaticsDisplay implements Observer,DisplayElement {
    19     private Subject weatherData;
    20     private Data data;
    21 
    22     public StaticsDisplay(Subject weatherData){
    23         this.weatherData = weatherData;
    24         weatherData.registerObserver(this);
    25     }
    26     public void display() {
    27         System.out.println("StaticsDisplay:"+this.data);
    28     }
    29 
    30     public void update(Data data) {
    31         this.data = data;
    32         display();
    33     }
    34 }
      4.测试类
    1 public class Test {
    2     public static void main(String[] args){
    3         WeatherData weatherData = new WeatherData();
    4         CurrentConditionDisplay display1 = new CurrentConditionDisplay(weatherData);
    5         StaticsDisplay display2 = new StaticsDisplay(weatherData);
    6         weatherData.setData(new Data(12,22,33.1f));
    7         weatherData.setData(new Data(2.3f,42,13));
    8     }
    9 }

      5.测试结果如下

      

     四 Java内置的观察者模式

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

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

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







  • 相关阅读:
    监控里的主码流和子码流是什么意思
    监控硬盘容量计算
    一个能让你了解所有函数调用顺序的Android库
    电工选线
    oracle linux dtrace
    list all of the Oracle 12c hidden undocumented parameters
    Oracle Extended Tracing
    window 驱动开发
    win7 x64 dtrace
    How to Use Dtrace Tracing Ruby Executing
  • 原文地址:https://www.cnblogs.com/bwyhhx2018/p/10658285.html
Copyright © 2011-2022 走看看