设计模式之观察者模式

第一次学习观察者模式已经是六七年以前,那个时候只是机械的去理解。也知道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的麻烦。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值