Java设计模式(十)

Java设计模式(十)

------------观察者模式

引入

我们这里利用《Head.First.设计模式》中的那个气象站的经典的例子坐引。

我们需要建立一个该气象站,它必须建立在我们专利申请中的WeatherD ata对象上,由WeatherData对象负责追踪目前的天气状况(温度、湿度、气压)。我们还要建立一个应用,有三种布告板,分别显示目前的状况、气象统计及简单的预报。当WeatherObject对象获得最新的测量数据时,三种布告板必须实时更新。

而且,我们还希望它是一个可以扩展的气象站,也就是允许其他开发人员可以写出自己的气象布告板,并插入此应用中。

好了,下面的例子我们都将围绕这个例子进行。

定义与角色

定义

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

角色

抽象主题角色

public interface Subject {

 

       public void addObserver(Observer o);

 

       public void removeObserver(Observer o);

 

       public void notifyObserver();

 

}

 

具体主题角色

public class WeatherData implements Subject {

       List<Observer> listeners = new ArrayList<Observer>();

 

       public int getTemperature() {

              return 0;

       }

 

       public double getHumidity() {

              return 0.53;

       }

 

       int getPressure() {

              return 30;

       }

       // 对外暴露接口

       public void measurementsChanged() {

              this.notifyObserver();

       }

       @Override

       public void addObserver(Observer o) {

              // TODO Auto-generated method stub

              listeners.add(o);

       }

       @Override

       public void notifyObserver() {

              // TODO Auto-generated method stub

              int t = this.getTemperature();

              double h = this.getHumidity();

              int p = this.getPressure();

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

                     Observer listener = listeners.get(i);

                     listener.onWebtherChange(t, h, p);

              }

       }

       @Override

       public void removeObserver(Observer o) {

              // TODO Auto-generated method stub

              listeners.remove(o);

       }

}

 

抽象观察者角色

public interface Observer {

 

       public void onWebtherChange(int t, double h, int p);

 

}

 

具体观察者角色

public class HWeatherPanel implements Observer {

 

       public WeatherData data;

 

       public HWeatherPanel(WeatherData data) {

              this.data = data;

              data.addObserver(this);

       }

 

       @Override

       public void onWebtherChange(int x, double h, int p) {

              // TODO Auto-generated method stub

              System.out.println("更新湿度面板,最湿度是 " + h);

       }

 

}

public class PWeatherPanel implements Observer {

       public WeatherData data;

 

       public PWeatherPanel(WeatherData data) {

              this.data = data;

              data.addObserver(this);

       }

 

       @Override

       public void onWebtherChange(int x, double h, int p) {

              // TODO Auto-generated method stub

              System.out.println("更新压力面板,最新压力是 " + p);

       }

 

}

public class TWeatherPanel implements Observer {

       public WeatherData data;

 

       public TWeatherPanel(WeatherData data) {

              this.data = data;

              data.addObserver(this);

       }

 

       @Override

       public void onWebtherChange(int x, double h, int p) {

              // TODO Auto-generated method stub

              System.out.println("更新温度面板,最新温度是 " + x);

       }

 

}

 

客户调用

public class MyTest {

 

       /**

        * @param args

        */

       public static void main(String[] args) {

              // TODO Auto-generated method stub

              WeatherData data = new WeatherData();

              HWeatherPanel hp = new HWeatherPanel(data);

              PWeatherPanel pp = new PWeatherPanel(data);

              TWeatherPanel tp = new TWeatherPanel(data);

 

              data.measurementsChanged();

       }

 

}

打印结果:

          更新湿度面板,最湿度是 0.53

          更新压力面板,最新压力是 30

          更新温度面板,最新温度是 0

 

Java中内置的观察者模式

到目前为止,我们已经从无到有地完成了观察者模式,但是,JavaAAPI有内置的观察者模式。java.util包(package)内包含最基本的Observer接口与Observable类,这和我们的Subject接口与Observer接口很相似。Observer接口与Observable类使用上更方便,因为许多功能都已经事先准备好了。

使用

接口 Observer

一个可在观察者要得到 observable 对象更改通知时可实现 Observer 接口的类。

update(Observable o, Object arg)

很显然 这个Observer接口就是对应我们自己实现中的Observer接口,update(Observable o, Object arg)方法就对应我们的onWebtherChange(int t, double h, int p)方法这与我们的想法甚至名称都是一致的。

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

 

由上表可以看出Observable类对应我们自己实现中的Subject接口,由于它是一个类,对于想要扩展的朋友就显得无能为力了,但是对于一般的观察者应用已经足够使了。

区别

我们不难发现,这个函数表中多个一个change的概念(setChanged()hasChanged()clearChanged())它的引入是为了在更新观察者时,有更多的弹性,你可以更适当地通知观察者。比方说,如果没有setChanged()方法,我们的气象站测量是如此敏锐,以致于温度计读数每十分之一度就会更新,这会造成WeatherData对象持续不断地通知观察者,我们并不希望看到这样的事情发生。如果我们希望半度以上才更新,就可以在温度差距到达半度时,调用setChanged(),进行有效的更新。你也许不会经常用到此功能,但是把这样的功能准备好,当需要时马上就可以使用。总之,你需要调用setChanged(),以便通知开始运转。如果此功能在某些地方对你有帮助,你可能也需要clearChanged()方法,将changed状态设置回false。另外也有一个hasChanged()方法,告诉你changed标志的当前状态。

总结

优势

主题对象与观察者对象之间的松耦合,主题对象只知道Obserser接口,并不关谁实现了该接口以及怎么实现的,一旦有新类型观察者出现,我们只要把它注册到主题中就可以了,不用修改任何代码。

主要程序设计应用

这种设计模式广泛用于数据或状态的变化引起的界面刷新工作。

比如一个股票数据(价格)发生变化,可能会影响几个视图的更新(实时图,表图,甚至要入库操作。。。),我们就需要把这几个视图和操纵数据库的类作为观察者,注册到相应主题中去。

你可能感兴趣的:(Java设计模式(十))