Design pattern学习笔记 – observer pattern

Design pattern学习笔记 – observer pattern

1. 问题引入—气象观测站

    实现一个气象观测站系统,从物理设备中获取天气变化(主要包括humidity, temperature, pressure),依据这些设备变化提供当前天气、天气统计、天气预报三种气象报告方式;此外对该气象站系统有一定的扩展需求,以后可方便添加其他自定义的气象报告方式。下图展示需求:


    现有的WeatherData对象结构:

public class WeatherData {

       public float getTemperature(){

              float temperature = 43;

              return temperature;

       }

       public float getHumidity(){

              float humidity = (float) 56.5;

              return humidity;

       }

       public float getPressure(){

              float pressure = 100;

              return pressure;

       }

       public void measurementsChanged(){

              //每次气候相关参数发生变化时被调用

       }

}

2. 分析需求

    a. WeatherData类有一组get方法,可以从物理设备获取temperature, humidity, pressure

    b. 只要气候参数发生变化,measurementsChanged方法就会被调用

    c. 需要实现三种气候报告的展示:当前、统计、预报

    d. 系统要能支持以后自定义的气候报告展示

3. 初始的实现

    public voidmeasuremensChanged(){

              //每次气候相关参数发生变化时被调用

              float temp = getTemperature();

              float humidity = getHumidity();

              float pressure = getPressure();

             

              conditionsDisplay.update(temp, humidity,pressure);

              statisticsDisplay.update(temp, humidity,pressure);

              forecastDisplay.update(temp, humidity,pressure);

       }

    问题:

    a. 对实现编程而不是对接口编程

    b. 增加新的气候报告展示方式需要修改已有代码

    c. 在运行期间无法改变展示方式

    d. 没有封装变化

    e. 破坏了对WeatherData的封装

    f.  三个display相同的update方法,没有实现接口

4. 定义观察者模式

    报纸订阅:出版社发行报纸;消费者通过邮局订阅报纸,有新报纸就会送达消费者;消费者不再需要报纸时,取消订阅,以后报纸就不再送给消费者;消费者退订和增加订阅并不影响其他订阅的消费者。

    publishers + subscribers =observer pattern = subject + observers

The Observer Pattern defines a one-to-many dependency between objects sothat when one object changes state, all of its dependents are notified andupdated automatically.

观察者模式定义了一种一对多的依赖关系,当“一”发生变化时,依赖的“多”能收到通知并自动更新。

5. observer pattern的类图

   几个问题:

Q.   为什么是一对多的依赖关系?

A.   主题只有一个,观察者有多个,观察者依赖于主题的状态进行更新。

Q. 是怎样形成这样的依赖的?

A.按照面向对象的设计原则,相同的代码应该出现在一个地方且只出现在这一个地方,主题拥有“状态”和对“状态”控制的代码;观察者不拥有“状态”,但是需要依据“状态”进行更新。

    Q. 为什么说观察者模式是松散耦合的?

    a. subject只知道observer实现了一个observer接口

    b. 到执行时才确定调用哪个observer

    c. 添加新的observer时,不用修改subject

    d. 更容易复用observer和subject

    e. 修改observer或者subject时不相互影响

6. 应用观察者模式实现气象观测站系统

    类图

    

    代码

    public interfaceSubject {

      

       public void registerObserver(Observer O);

       public void removeObserver(Observer o);

       public void notifyObserver();

 

    }

    public interfaceObserver {

       public void update(float temp, float humidity, floatpressure);

    }

    public interfaceDislpayElement {

       public void display();

    }

    public classWeatherData implements Subject{

       private ArrayList<Observer> observers;

       private float temperature;

       private float humidity;

       private float pressure;

      

       public WeatherData(){

              observers = newArrayList<Observer>();

       }

 

       public void notifyObserver() {

              // TODO Auto-generated method stub

              for(int i = 0; i < observers.size();i++){

                     Observer o = this.observers.get(i);

                     o.update(temperature, humidity, pressure);

              }

       }

 

       public void registerObserver(Observer o) {

              // TODO Auto-generated method stub

              int i = observers.indexOf(o);

              if(i >= 0)

                     observers.remove(i);

       }

 

       public void removeObserver(Observer o) {

              // TODO Auto-generated method stub

              observers.add(o);

       }

      

       public void measurementsChanged(){

              notifyObserver();

       }

      

       public void setMeasurements(float temp, float humidity, floatpressure){

              this.temperature = temp;

              this.humidity = humidity;

              this.pressure = pressure;

             

              measurementsChanged();

       }

 

    }

    public classConditionsDisplay implements Observer, DislpayElement{

       private float temp;

       private float humidity;

       private Subject weatherData;

      

       public ConditionsDisplay(WeatherData weatherData){

              this.weatherData = weatherData;

              weatherData.registerObserver(this);

       }

 

       public void update(float temp, float humidity, floatpressure) {

              // TODO Auto-generated method stub

              this.temp = temp;

              this.humidity = humidity;

             

              display();

       }

 

       public void display() {

              // TODO Auto-generated method stub

              //展示代码

       }

 

    }

    问题:

    a. is update() the bestplace to call display?

    b. why did you store areference to the Subject? It doesn't look like you use it again after theconstructor?

    c. push or pull?

7. 使用java内置的observer pattern

    

    Observable的实现

    private Vector obs;

    public voidnotifyObservers() {

       notifyObservers(null);

    }    

    public voidnotifyObservers(Object arg) {   

        Object[]arrLocal;

 

       if (!changed)

           return;

        arrLocal =obs.toArray();

       clearChanged();

 

        for (int i =arrLocal.length-1; i>=0; i--)

           ((Observer)arrLocal[i]).update(this, arg);

    }

    public synchronizedvoid addObserver(Observer o) {

        if (o == null)

           throw new NullPointerException();

       if (!obs.contains(o)) {

           obs.addElement(o);

       }

    }

    public synchronizedvoid deleteObserver(Observer o) {

       obs.removeElement(o);

    }

    protectedsynchronized void setChanged() {

       changed = true;

    }

    使用java内置的Observer实现气象观测站

    public classWeatherData extends Observable{

       private float temperature;

       private float humidity;

       private float pressure;

      

       public WeatherData() {

       }     

       public void measurementChanged(){

              setChanged();

              notifyObservers();

       }     

       public void setMeasurements(float temperature, floathumidity, float pressure){

              this.temperature = temperature;

              this.humidity = humidity;

              this.pressure = pressure;

             

              measurementChanged();

       }

       public float getTemperature() {

              return temperature;

       }

       public float getHumidity() {

              return humidity;

       }

       public float getPressure() {

              return pressure;

       }

    }

    public classConditionsDisplay implements Observer{

       Observable observable;

       private float temperature;

       private float humidity;

      

       public ConditionsDisplay(Observable observable){

              this.observable = observable;

              observable.addObserver(this);

       }

       public void update(Observable o, Object arg) {

              // TODO Auto-generated method stub

              if(o instanceof WeatherData) {

                     WeatherData weatherData = (WeatherData)o;

                     this.temperature =weatherData.getTemperature();

                     this.humidity = weatherData.getHumidity();

                     display();

              }

       }     

       public void display(){

             

       }

    }

    java内嵌observable的dark side

    1. Observable是类不是接口

    2. 关键方法是protect的(setChanged)

8.总结

    OO的原则

    a. encapsulate what varies.

    b. favor composition overinheritance

    c. program to interfaces,not implementations.

    d. strive for looselycoupled designs between objects that interact.

    observer模式遵循以上原则

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值