java设计模式—观察者模式

         当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。

        背景介绍:现在有这样一个任务,我们要做一个系统,从气象站读取数据,并随时更新三个公告板,目前状况(温度,湿度,气压),气象统计,天气预报。


先看一个不太合理的设计:



        代码很简单,其中三个get方法分别用来获取温度,湿度和气压,下面三行用来更新布告板,传入的参数有三个,温度,湿度和气压,但,这种设计,显然不好。

        上面这种实现方法,是针对具体编程,会导致我们以后再增加布告板或者删除布告板的时候必须修改程序,而面向对象的一个设计原则就是针对接口编程。还有,改变的地方,最好要封装起来。

        那,有没有解决上面提到的问题的方法呢?有!答案是观察者模式。

       我们先看看观察者模式,再看怎么运用到气象观测当中去。


       这是观察者模式的一个示意图,主要包含两部分,主体对象和观察和者对象。主体对象管理某些数据,当主题内的数据发生变化,就会通知观察者。已经订阅(注册)了主题的观察者便能在主题数据发生变化的时候受到更新。并且,只有在观察者对象里面的对象,才能收到通知。

      那,如何利用观察者模式来实现气象预测呢?

      首先看一下观察者模式的类图:

    


Subjecct接口:主题接口,对象使用此接口注册为观察者,或者把自己从观察者中删除。

Observer接口:所有潜在的观察者都必须实现的接口,只有update一个方法,当主题状态改变时被调用。

ConcreteSubject:除了实现了主题接口,还增加了notifyObserver方法,用于在状态改变时更新所有的当前观察者。


下面是设计图:



然后是实现的代码:

       首先是是三个接口。主题接口,观察者接口,所有的气象组件都要实现此接口,这样,主题在需要通知观察者时,有了一个共同的接口。然后是布告板接口,我们也要建立这样一个接口,布告板只需要实现display方法。



        然后是WeatherData类,需要实现主题接口。WeatherData类声明了一个ArrayList类型的变量,用来存储观察者,然后有几个方法,注册观察者,删除观察者,通知观察者更新。具体代码如下:


       下面是一个布告板的实现代码,实现了Observer接口,所以可以从WeatherData对象中获取改变,还实现了DiaplayElement接口。当update方法被调用了,就把温度和湿度保存起来,然后调用display方法显示出来。


最后是一个测试程序:


实现结果如下:



还有一种办法就是,可以使用java内置的观察者模式,java.util包内含最基本的Observer接口和Observable类。

不过Observable也是有缺点的:

1,可观察者是一个类而非一个接口,它甚至没有实现一个接口,这将限制它的使用和复用功能。
2,Observable已经是一个类,必须设计一个类继承它,如果某类想同时拥有Observable和另一个超类的功能,会陷入两难。

3,setChanged方法的修饰符为保护,这将意味着,除非你继承这个类,否则无法创建Observable实例并组合到自己的对象中。违反了设计原则“多用组合,少用继承”。

    最后,我们的目标是,为对象之间的松耦合设计而努力。

    书中代码来自《Head First设计模式》