zoukankan      html  css  js  c++  java
  • 《Head First 设计模式》之观察者模式——天气显示

    观察者模式(Observer)

      ——在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。

    (出版者Subject+订阅者Observer=观察者模式)

    • 特点:定义并维护对象之间的一对多关系
    • 原则:为交互对象之间的松耦合设计而努力
    • 示例(气象站类图)

    三个接口:

     1 public interface Subject{
     2     public void registerObserver(Observer o);//注册观察者
     3     public void removeOberver(Observer o);//删除观察者
     4     public void notifyObserver();//通知观察者
     5 }
     6 
     7 public interface Observer{
     8     public void update(float temp, float humidity, float pressure);
     9 }
    10 
    11 public interface DisplayElement{
    12     public void display();
    13 }

    在WeatherData中实现主题接口:

     1 public class WeatherData implements Subject{
     2     private ArrayList observers;//记录观察者
     3     private float temperature;
     4     private float humidity;
     5     private float pressure;
     6     
     7     public WeatherData(){
     8         observers = new ArrayList();
     9     }
    10     
    11     public void registerObserver(Observer o){//注册观察者
    12         observers.add(o);
    13     }
    14     public void removeOberver(Observer o){//删除观察者
    15         int i = observers.indexOf(o);
    16         if(i >= 0){
    17             observers.remove(0);
    18         }
    19     }
    20     public void notifyObservers(){
    21         for(int i = 0; i < observers.size(); i++){ //通知每一个观察者
    22             Observer observer = (Observer)observers.get(i);
    23             observer.update(temperature, humidity, pressure);
    24         }
    25     }
    26     public void measurementsChanged(){
    27         notifyObservers();
    28     }
    29     public void setMeasurements(float temp, float hum, float pre){
    30         this.temperature = temp;
    31         this.humidity = hum;
    32         this.pressure = pre;
    33         measurementsChanged();
    34     }
    35 }

    实现CurrentConditionDisplay.java

     1 public class CurrentConditionsDisplay implements Observer, DisplayElement{
     2     private float temperature;
     3     private float humidity;
     4     private Subject weatherData;
     5     
     6     public CurrentConditionsDisplay(Subject weatherData){//构造器需要weatherData对象作为注册之用
     7         this.weatherData = weatherData;
     8         weatherData.registerObserver(this);
     9     }
    10     public void update(float temp, float humidity, float pressure){
    11         this.temperature = temp;
    12         this.humidity = humidity;
    13         display();
    14     }
    15     public void display(){
    16         //输出
    17     }
    18 }

    测试程序:

     1 public class WeatherStation {
     2 
     3         public static void main(String[] args) {
     4             WeatherData weatherData = new WeatherData();//建立weatherData对象
     5 
     6             CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
     7             StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
     8             ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);//将对象传给三个Observer,即add观察者
     9 
    10             weatherData.setMeasurements(80, 65, 30.4f);
    11             weatherData.setMeasurements(82, 70, 29.2f);
    12             weatherData.setMeasurements(78, 90, 29.2f);
    13         }
    14     }

     


     

    Java内置的观察者模式

      上述示例实现信息由Subject “推送(push)” 至Observer,使用Java内置的观察者模式可以使用推(push)或拉(pull)的方式传送数据。不同的是WeatherData现在扩展自Observable类,并继承到一些add、delete、notify观察者的方法。

    Subject -> java.util.Observable(类)

    Observer -> java.util.Observer(接口)

    Observable如何送出通知?

      首先需要利用扩展 java.util.Observable 接口产生“可观察者”类(想要进行通知,则必须调用Observable类的setChanged方法,但是Observable的setChanged方法为protected,故只能使用继承来实现自己的主题对象),然后:

    1. 调用setChanged(),标记状态已经改变的事实;
    2. 调用notifyObservers()中的一个:notifyObservers() 或 notifyObservers(Object arg)

    Observer如何接收通知?

    update(Observable o, Object arg)  :主题Observable作为第一变量,好让观察者知道是哪个主题通知它的。Object arg正是传入notifyObservers(Object arg)的数据对象,如果没有说明则为空。

    若想push数据给观察者,可以把数据作数据对象传送给notifyObservers(Object arg)方法。否则,观察者就必须从可观察者对象中pull数据。如何拉数据?

     WeatherData.java

     1 public class WeatherData extends Observable{
     2     private float temperature;
     3     private float humidity;
     4     private float pressure;
     5     
     6     public WeatherData(){ } //无需建立观察者列表ArrayList了
     7     public void measurementsChanged(){
     8         setChanged();//状态已经改变
     9         notifyObservers();//pull
    10     }
    11     public void setMeasurements(float temp, float hum, float pre){
    12         this.temperature = temp;
    13         this.humidity = hum;
    14         this.pressure = pre;
    15         measurementsChanged();
    16     }
    17     public float getTemperature(){
    18         return temperature;
    19     }
    20     public float gethumidity(){
    21         return humidity;
    22     }
    23     public float getpressure(){
    24         return pressure;
    25     }
    26 }

    CurrentConditionDisplay.java

     1 public class CurrentConditionsDisplay implements Observer, DisplayElement{
     2     private float temperature;
     3     private float humidity;
     4     Observable observable;
     5     
     6     public CurrentConditionsDisplay(Observable observable){
     7         this.observable = observable;
     8         observable.addObserver(this);
     9     }
    10     public void update(Observable o, Object arg){
    11         if(o instanceof WeatherData){
    12             WeatherData weatherData = (WeatherData)o;
    13             this.temperature = weatherData.getTemperature();
    14             this.humidity = weatherData.gethumidity();
    15             display();
    16         }
    17     }
    18     public void display(){
    19         //输出
    20     }
    21 }

    notice:

    1. 不想推送的时候,不调用setChanged()方法即可
    2. 通知顺序不依赖于注册的顺序(即主题通知观察者的顺序与添加观察者的顺序无关)
    3. setChanged()方法的必要性:若无,则温度计读数每十分之一度就会更新,造成WeatherData对象持续不断地通知观察者。若希望温差达到半度时更新,就调用setChanged()。有更多的弹性,更适当地通知观察者。

    使用Java自带的观察者模式的缺点:

    1. Observable是一个类,而不是一个接口,导致Observable类的扩展性不高,不如自己实现的观察者模式灵活
    2. Observable将某些方法保护了起来(setChanged()和clearChanged()为protected),这意味着除非继承自Observable,否则将有关键的方法不能调用。导致无法通过组合的方式使其它类获得Observable类的功能。违反了设计原则“多用组合,少用继承”。
  • 相关阅读:
    c/cpp枚举练习
    数据类型的标识
    引用变量
    cocos2dx 3.3 笔记
    希望获取到页面中所有的checkbox怎么做?
    如何判断某变量是否为数组数据类型?
    驼峰函数写法
    trim()函数
    js 获取页面可视区域宽高
    全屏滚动插件
  • 原文地址:https://www.cnblogs.com/-1307/p/6434675.html
Copyright © 2011-2022 走看看