• JAVA设计模式之观察者模式


    气象站系统:气象站可以通过物理装置取得气象信息,WeatherData对象可以通过气象站提供的外部接口获取气象信息。

    需求:WeatherData获取最新数据时,需要实时更新三个布告板的气象数据。三个布告板分别是:目前状况、气象统计、天气预报。

    一、整理分析:

    1.WeatherData有三个getter方法getTemperature(),getHumidity(),getPressure()分别获取温度、湿度、气压值;

    2.当数据改变时,WeatherData有个方法measurementsChanged()会被调用(我们不关心如何被调用),此时需更新三个布告板的气象信息;

    3.系统需可扩展,可随时新增或者删除布告板。

    第一次尝试:

     1 public class WeatherData {
     2     
     3     public void measurementsChanged() {
     4         float temperature = getTemperature();
     5         float humidity = getHumidity();
     6         float pressure = getPressure();
     7         //目前状况布告板更新
     8         currentConditionsDisplay.update(temperature, humidity, pressure);
     9         //气象统计布告板更新
    10         statisticsDisplay.update(temperature, humidity, pressure);
    11         //天气预报布告板更新
    12         forecastDisplay.update(temperature, humidity, pressure);
    13     }
    14     
    15     //WeatherData的其他方法
    16     
    17 }

    存在的问题:针对实现编程,会难以扩展和维护,如果需要新增或者删除布告板,必须修改该程序。

    例如报社,订阅报纸后,报社会定期给你邮寄报纸,停止订阅后报社便停止邮寄。我们把报社改称为“主题 Subject”,把订阅者改成为“观察者 Observer”来研究观察者模式。

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

    主题不需要知道观察者具体是谁,只需要知道观察者实现了Observer接口,并不关心观察者具体做了哪些事,这种交互对象间的松耦合是设计中追求的原则,下面看主题Subject和观察者Observer接口代码:

    1 /*观察者*/
    2 public interface Observer {
    3     public void update(float temp, float humidity, float pressure);
    4 }
    1 /*主题*/
    2 public interface Subject {
    3     /*注册成为观察者*/
    4     public void registerObserver(Observer o);
    5     /*移除观察者*/
    6     public void removeObserver(Observer o);
    7     /*通知所有观察者*/
    8     public void notifyObservers();
    9 }   
    1 public interface DisplayElement {
    2     /**
    3      * 布告板都实现该接口,调用display来展示气象信息
    4      */
    5     public void display();
    6 }

    现在让WeatherData实现主题接口:

     1 public class WeatherData implements Subject {
     2     private List<Observer> observerList;
     3     private float temperature;
     4     private float humidity;
     5     private float pressure;
     6     
     7     public WeatherData() {
     8         observerList = new ArrayList<Observer>();
     9     }
    10     public void registerObserver(Observer o) {
    11         observerList.add(o);
    12     }
    13 
    14     public void removeObserver(Observer o) {
    15         int i = observerList.indexOf(o);
    16         if (i >= 0) {
    17             observerList.remove(i);
    18             System.out.println(o.getClass().getName() + " is removed.");
    19         }
    20     }
    21 
    22     public void notifyObservers() {
    23         for (Observer o : observerList) {
    24             o.update(temperature, humidity, pressure);
    25         }
    26     }
    27     /*数据更新时,通知所有观察者*/
    28     public void measurementsChanged() {
    29         notifyObservers();
    30     }
    31 
    32 }

    布告板实现观察者接口:

     1 /*目前状况布告板*/
     2 public class CurrentConditionsDisplay implements Observer, DisplayElement {
     3 
     4     private float temperature;
     5     private float humidity;
     6     private Subject weatherData;
     7     
     8     public CurrentConditionsDisplay(Subject subject) {
     9         this.weatherData = subject;
    10         weatherData.registerObserver(this);
    11     }
    12     
    13     public void removeObserver() {
    14         weatherData.removeObserver(this);
    15     }
    16 
    17     public void update(float temp, float humidity, float pressure) {
    18         this.temperature = temp;
    19         this.humidity = humidity;
    20         display();
    21     }
    22     
    23     public void display() {
    24         System.out.println("CurrentConditionsDisplay conditions:" + temperature + "F degrees and " + humidity + "% humidity");
    25     }
    26 
    27 }
    28 
    29 /*天气预报布告板*/
    30 public class ForecastDisplay implements Observer, DisplayElement {
    31 
    32     private float temperature;
    33     private float pressure;
    34     private Subject weatherData;
    35     
    36     public ForecastDisplay(Subject subject) {
    37         this.weatherData = subject;
    38         weatherData.registerObserver(this);
    39     }
    40     
    41     public void removeObserver() {
    42         weatherData.removeObserver(this);
    43     }
    44 
    45     public void update(float temp, float humidity, float pressure) {
    46         this.temperature = temp;
    47         this.pressure = pressure;
    48         display();
    49     }
    50     
    51     public void display() {
    52         System.out.println("ForecastDisplay conditions:" + temperature + "F degrees and " + pressure + "Pa");
    53     }
    54 
    55 }
    56 
    57 /*气象状况布告板略*/

    代码测试:

     1 public class ObserverTest {
     2     
     3     @Test
     4     public void test() {
     5         WeatherData weatherDate = new WeatherData();
     6         CurrentConditionsDisplay ccDisplay = new CurrentConditionsDisplay(weatherDate);
     7         ForecastDisplay fcDisplay = new ForecastDisplay(weatherDate);
     8         weatherDate.setMeasurements(12.3f, 38.6f, 130f);
     9         ccDisplay.removeObserver();
    10         weatherDate.setMeasurements(12.3f, 38.6f, 130f);
    11         fcDisplay.removeObserver();
    12         weatherDate.setMeasurements(12.3f, 38.6f, 130f);
    13         System.out.println("notify ok");
    14     }
    15 }

    运行结果:

    1 CurrentConditionsDisplay conditions:12.3F degrees and 38.6% humidity
    2 ForecastDisplay conditions:12.3F degrees and 130.0Pa
    3 com.project.design.observer.CurrentConditionsDisplay is removed.
    4 ForecastDisplay conditions:12.3F degrees and 130.0Pa
    5 com.project.design.observer.ForecastDisplay is removed.
    6 notify ok

    Java JDK中也存在已经定义好的观察者模式,在java.util包中(Observable(主题), Observer(观察者)),大家有兴趣可以自己了解下。java中的观察者可以手动从主题中拉取数据,主题也可以主动去推送数据。

  • 相关阅读:
    CVPR-2021-Papers
    caffe中使用多个GPU的方法
    大道至简!深度解读CVPR2021论文RepVGG
    195上的rknn
    RKNN1.6下载路径
    基于深度学习的2D和3D仿射变换配准
    涵盖18+ SOTA GAN实现,开源工程StudioGAN火了
    基于opencv实战眼睛控制鼠标
    S7-200SMART PLC与变频器MODBUS RTU通讯与SMART LINE系列屏控制(案例三)
    Java异常处理学习
  • 原文地址:https://www.cnblogs.com/bearduncle/p/8086286.html
Copyright © 2020-2023  润新知