设计模式之观察者模式

来源:互联网 发布:java中多继承 编辑:程序博客网 时间:2024/06/06 01:12

第一次学习观察者模式已经是六七年以前,那个时候只是机械的去理解。也知道JAVA中AWT和SWING中使用了观察者模式。但是没有真正去理解透(当然,现在也可能没有真正理解透,但是比那个时候要好很多)。后面陆续也看过几次,都没有真正去思考观察模式的设计理念。现在有时间了,再重新学习了一遍,发现又领悟到不少,再此记录一下本人的学习心得。欢迎各位大拿,拍砖!!

观察者模式概念

  1. 顾名思义,多个观察者关注同一个被观察者。只要被观察者的状态发生变化,所有 观察者都会采取对应的行为。举个例子,校花一般都是有很多追求者的,校花的生日到了,众多追求者会采取行动去取悦校花,都希望打动校花。这其中,校花是被观察者,追求者是观察者,生日是状态变化。

观察者模式中角色

  1. 抽象观察者:这里的抽象观察者有可能是接口或者是抽象类。主要是声明了观察者共同的行为,具体的观察者需要去实现这个行为。
  2. 具体观察者:实现抽象观察者接口或类中声明的方法,当被观察者状态发生变化时,调用观察者的方法。
  3. 抽像主题(被观察者):被观察者也叫主题(subject)。它是所有观察者时刻关注的目标,主题的属性发生变话,会影响到观察者的行为。通常情况下,使用抽象类或者接口表示。(也可以不使用抽象主题)。
  4. 具体主题(被观察者):实现抽象主题,具体被观察者所关注的对象。状态真正承载的载体

如何设计观察者

1.在JAVA中使用观察者模式进行编程,需要确定编程的对象。根据观察者模式中的角色,我们可以很容易设计出,观察者接口Observer,具体观察者ObserverImpl,抽象主题Observable,具体观察者ObservableImpl。
2. 观察者需要时刻关注到主题的动态变化,则所有观察者需要将自己注册到一个集中管理的地方,等主题状态发生变化时,能够通知观察者。这就要求主题能够将观察者进行集中管理(采用集合等方式)。反应到JAVA类中时,主题中要提供方法供客户端调用进行增加,删除观察者。
3. 主题类中除了提供集中管理观察者的机制,增加,删除观察者的方法,还应该提供通知观察者的方法。即主题状态发生变化或发生一个事件,能够通知观察者去采取对应的行为。
4. 根据上述1~3步骤分析,大致可以分析出观察者的基本的类图关系。
这里写图片描述

设计原则

  1. 观察者模式中,主题要可以动态管理注册的观察者,即增加或者删除观察者不需要修改主题中的代码,这要求主题中维护的观察者类型是父类型或接口类型。实际操作时,传递具体类型即可,这也符合面向抽象编程,其实就是依赖倒转原则。即依赖抽象而不是依赖具体。
  2. 在实际设计过程中,观察者也可以持有被观察者的引用,根据具体情况分析,即观察者接到通知后,调用被观察者的方法处理一些其他业务逻辑。

JDK中使用观察者

  1. 在JDK中也提供了对观察者模式的支持。被观察者类Observable,观察者接口Observer。其中被观察者中含有两个属性changed,vetor分别用来表示状态值和管理观察者。观察者接口中定义了一个更新接口。
public interface Observer {    /**     * This method is called whenever the observed object is changed. An     * application calls an <tt>Observable</tt> object's     * <code>notifyObservers</code> method to have all the object's     * observers notified of the change.     *当被观察者对象发生改变,调用该方法。应用可以调用被观察者的notifyObservers方法通知观察者     * @param   o     the observable object.     * @param   arg   an argument passed to the <code>notifyObservers</code>     *                 method.     */    void update(Observable o, Object arg);}
  1. 被观察者对象是类Observable,代表被观察者对象。其中有2个属性,chanage和vetor。分别用来代表状态和管理观察者。代码很简单,不作具体分析。
public class Observable {    private boolean changed = false;    private Vector obs;//管理观察者    public Observable() {        obs = new Vector();    }    /**     *注册观察者     */    public synchronized void addObserver(Observer o) {        if (o == null)            throw new NullPointerException();        if (!obs.contains(o)) {            obs.addElement(o);        }    }    /**      * 删除观察者     */    public synchronized void deleteObserver(Observer o) {        obs.removeElement(o);    }    /**      *参考notifyObservers(object)     */    public void notifyObservers() {        notifyObservers(null);    }    /**     * 被观察者对象object状态发生变化,则通知对象object的所有的观察者。然后调用    *       clearChange方法表明,被观察者对象状态不再发生改变。     */    public void notifyObservers(Object arg) {        /*         * a temporary array buffer, used as a snapshot of the state of         * current Observers.         */        Object[] arrLocal;        synchronized (this) {            /* We don't want the Observer doing callbacks into             * arbitrary code while holding its own Monitor.             * The code where we extract each Observable from             * the Vector and store the state of the Observer             * needs synchronization, but notifying observers             * does not (should not).  The worst result of any             * potential race-condition here is that:             * 1) a newly-added Observer will miss a             *   notification in progress             * 2) a recently unregistered Observer will be             *   wrongly notified when it doesn't care             */            if (!changed)                return;            arrLocal = obs.toArray();            clearChanged();        }        for (int i = arrLocal.length-1; i>=0; i--)            ((Observer)arrLocal[i]).update(this, arg);    }    /**     * Clears the observer list so that this object no longer has any observers.     */    public synchronized void deleteObservers() {        obs.removeAllElements();    }    /**      * 设置观察者的状态     */    protected synchronized void setChanged() {        changed = true;    }    /**     *  重置观察者的状态     */    protected synchronized void clearChanged() {        changed = false;    }    /**     *状态是否变化,表示被观察者状态变化     */    public synchronized boolean hasChanged() {        return changed;    }    /**     * 返回当前注册观察者个数     */    public synchronized int countObservers() {        return obs.size();    }}

通知方式

  1. 被观察者通知观察者时,可以直接调用观察者的方法,也可以另外启用一个线程通知每一个观察者,或者采用远程方式通知观察者。
    这里写图片描述

总结

  1. 观察者模式在很多框架和容器中都有使用。tomcat容器监听各种事件,zkClient中注册观察者,省却了开发人员反复注册的watcher的麻烦。
原创粉丝点击