观察者模式(Observer Pattern)

设计模式-观察者模式(上)
 
本文参考Head First设计模式一书,感觉书中的例子实在很好,很贴切。对模式的知识点进行总结,并对书的源码做了一定注释。
 
观察者模式要点有二:主题和观察者。
最贴切的案例是:杂志订阅,杂志是主题,观察者是订阅者。当出版新杂志时候,这个事件会自动通知所有的订阅者。
根据OO基本原则,应该针对接口编程(当然原因很多),主题和订阅者一般都作为接口。
 
下面是Head First的例子,是一个气象站,用户订阅气象信息的服务。
 
并且,最终用户所要的信息可能是:
 
针对这个需求,应用观察者模式来实现:
但是这个只是一个主题与观察者的设计,观察者自身还需要将信息显示出去。那么再用一个接口,专门来实现展示的功能。
 
 
实际上,上面的DisplayElement接口用再此处,本质上是策略模式的应用。
 
理解每个模式的特点对交流和设计都有很大帮助,当OO思想境修炼到很高的程度时,应该是忘掉所有的模式,而可以根据需要做出最佳设计,这个程度可以算手中无剑,心中有剑的地步。
 
下面是源码,只列出接口:
/** 
* 主题 
*/
 
public  interface Subject { 
   public  void registerObserver(Observer o); 
   public  void removeObserver(Observer o); 
   public  void notifyObservers(); 
}
 
/** 
* 观察者 
*/
 
public  interface Observer { 
   public  void update( float temp,  float humidity,  float pressure); 
}
 
/** 
* 布告板 
*/
 
public  interface DisplayElement { 
   public  void display(); 
}
 
测试main方法:
   public  static  void main(String[] args) { 
                 //创建主题 
    WeatherData weatherData =  new WeatherData(); 
                 //创建三个观察者 
    CurrentConditionsDisplay currentDisplay =  new CurrentConditionsDisplay(weatherData); 
    StatisticsDisplay statisticsDisplay =  new StatisticsDisplay(weatherData); 
    ForecastDisplay forecastDisplay =  new ForecastDisplay(weatherData); 
    HeatIndexDisplay heatIndexDisplay =  new HeatIndexDisplay(weatherData); 
                 //进行气象测量,主题的状态会因为测量值而改变 
    weatherData.setMeasurements(80, 65, 30.4f); 
    weatherData.setMeasurements(82, 70, 29.2f); 
    weatherData.setMeasurements(78, 90, 29.2f); 
  }
 
本例仅仅是为了说明这种模式,设计还远不够完美。实际上,主题中应该有一个线程去扫描状态的变化,当变化了,自动去调用measurementsChanged()方法。
 
观察者模式使用很普遍,GUI编程中事件注册就是典型的观察者模式的应用。
 
以上是自己实现的观察者模式,下文将讲述JDK所实现的观察者模式。

本文出自 “熔 岩” 博客,请务必保留此出处http://lavasoft.blog.51cto.com/62575/201617


设计模式-观察者模式(下)
 
观察者模式在Java中有两种实现方式,上文是一种方式,这种方式是自己写代码实现。
另一种方式是使用Java内置的观察者模式来实现。
 
相关的接口和类如下:
java.util.Observable   主题(可观察者)------class
java.util.Observer       观察者                     -------interface
 
 
相关的API如下:
1、java.util.Observable
Observable() 
          构造一个带有零个观察者的 Observable。 
方法摘要 
void addObserver(Observer o) 
          如果观察者与集合中已有的观察者不同,则向对象的观察者集合中添加此观察者。 
protected  void clearChanged() 
          指示对象不再改变,或者它已对其所有的观察者通知了最近的改变,所以 hasChanged 方法将返回 false。 
 int countObservers() 
          返回 Observable 对象的观察者数目。 
 void deleteObserver(Observer o) 
          从对象的观察者集合中删除某个观察者。 
 void deleteObservers() 
          清除观察者列表,使此对象不再有任何观察者。 
 boolean hasChanged() 
          测试对象是否改变。 
 void notifyObservers() 
          如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。 
 void notifyObservers(Object arg) 
          如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。 
protected  void setChanged() 
          标记此 Observable 对象为已改变的对象;现在 hasChanged 方法将返回 true。
 
2、java.util.Observer
void update(Observable o, Object arg) 
          只要改变了 observable 对象就调用此方法。
 
观察API可以发现, java.util.Observable已经对观察者进行管理了,不再需要主题追踪每个观察者了。
 
下面通过Java的内置的观察者模式来重写上个天气应用,部分类代码如下:
import java.util.Observable; 

public  class WeatherData  extends Observable { 
         private  float temperature; 
         private  float humidity; 
         private  float pressure; 

         public WeatherData() { 
        } 

         /** 
         * 测量值改变了 
         */
 
         public  void measurementsChanged() { 
                setChanged();              //设定改变了 
                notifyObservers();     //通知所有的观察者 
        } 

         /** 
         * 重新设定了测量值 
         */
 
         public  void setMeasurements( float temperature,  float humidity,  float pressure) { 
                 this.temperature = temperature; 
                 this.humidity = humidity; 
                 this.pressure = pressure; 
                measurementsChanged(); 
        } 

         public  float getTemperature() { 
                 return temperature; 
        } 

         public  float getHumidity() { 
                 return humidity; 
        } 

         public  float getPressure() { 
                 return pressure; 
        } 
}
 
public  interface DisplayElement { 
         public  void display(); 
}
 
import java.util.Observable; 
import java.util.Observer; 

public  class CurrentConditionsDisplay  implements Observer, DisplayElement { 
        Observable observable; 
         private  float temperature; 
         private  float humidity; 

         public CurrentConditionsDisplay(Observable observable) { 
                 this.observable = observable; 
                observable.addObserver( this); 
        } 

         public  void update(Observable obs, Object arg) { 
                 if (obs  instanceof WeatherData) { 
                        WeatherData weatherData = (WeatherData) obs; 
                         this.temperature = weatherData.getTemperature(); 
                         this.humidity = weatherData.getHumidity(); 
                        display(); 
                } 
        } 

         public  void display() { 
                System.out.println( "Current conditions: " + temperature 
                                +  "F degrees and " + humidity +  "% humidity"); 
        } 
}
 
看上面的代码,
java.util.Observable不是接口,是类,如果一个类想具有另一个超类的功能,同时还想拥有 Observable行为,就陷入两难地步。
 
实际上,Java内部使用观察者模式也很多,GUI的事件就是典型的观察者模式。
 

本文出自 “熔 岩” 博客,请务必保留此出处http://lavasoft.blog.51cto.com/62575/201633


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值