观察者模式

来源:互联网 发布:淘宝pu女包 编辑:程序博客网 时间:2024/05/21 00:20

平时写程序,基本是追求功能的实现,并不注重代码的质量及程序的设计,或许既有代码已经设计到了一些模式,但是没有发现,今天有时间,看看奥莱利O'Reilly的Head First系列书《设计模式》


以报纸和杂志的订阅为例子,可以这样想

  1. 报社出版报纸;
  2. 小红订了报纸,那么,如果以后报社有新报纸,只要小红还是订户,小红就会持续收到报纸,不间断;
  3. 小红失恋了,不想看报纸了,可以取消订阅,于是报社就不再给小红送了;
  4. 但是报社只要在运营,就会有源源不断的类似小红的客户前来订阅(或取消订阅);
从上面我们可以总结出:

  • 观察者模式 = 出版者 + 订阅者
出版者也称主题,即Subject,订阅者也可以称为观察者,即Observer。

这听起来是不是很像关注某个人的微博一样,例如当你成为赵丽颖的粉丝的时候,此时,赵丽颖就在扮演一个主题,你就是观察者。你可以持续地接收到赵丽颖更新的微博消息。

而在这里,赵丽颖也可以被当作是一名观察者去关注他人,这是很正常的,通常情况下,集两种角色于一身是非常合理的。

下面看一下观察者模式的真正定义:
  • 观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
在上面,赵丽颖作为一个主题,只需知道有哪些人关注了我,而不需要知道粉丝们具体身份细节。这实现了主题和观察者之间的松耦合。即便有新的观察者出现也不需要做修改,新观察者只需实现此观察者接口,然后注册为观察者即可。这样实现了主题和观察者的复用。

设计原则:为了交互对象之间的松耦合而努力。

书中介绍了以气象站广播天气为例,可以参考博客。

在java api中有内置的观察者模式。如java.util包内的Observer接口与Observable类。

java.util.Observer源码:

package java.util;/** * A class can implement the <code>Observer</code> interface when it * wants to be informed of changes in observable objects. * * @author  Chris Warth * @see     java.util.Observable * @since   JDK1.0 */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.     *     * @param   o     the observable object.     * @param   arg   an argument passed to the <code>notifyObservers</code>     *                 method.     */    void update(Observable o, Object arg);}

java.util.Observable源码:

package java.util;/** * This class represents an observable object, or "data" * in the model-view paradigm. It can be subclassed to represent an * object that the application wants to have observed. * <p> * An observable object can have one or more observers. An observer * may be any object that implements interface <tt>Observer</tt>. After an * observable instance changes, an application calling the * <code>Observable</code>'s <code>notifyObservers</code> method * causes all of its observers to be notified of the change by a call * to their <code>update</code> method. * <p> * The order in which notifications will be delivered is unspecified. * The default implementation provided in the Observable class will * notify Observers in the order in which they registered interest, but * subclasses may change this order, use no guaranteed order, deliver * notifications on separate threads, or may guarantee that their * subclass follows this order, as they choose. * <p> * Note that this notification mechanism is has nothing to do with threads * and is completely separate from the <tt>wait</tt> and <tt>notify</tt> * mechanism of class <tt>Object</tt>. * <p> * When an observable object is newly created, its set of observers is * empty. Two observers are considered the same if and only if the * <tt>equals</tt> method returns true for them. * * @author  Chris Warth * @see     java.util.Observable#notifyObservers() * @see     java.util.Observable#notifyObservers(java.lang.Object) * @see     java.util.Observer * @see     java.util.Observer#update(java.util.Observable, java.lang.Object) * @since   JDK1.0 */public class Observable {    private boolean changed = false;    private Vector obs;    /** Construct an Observable with zero Observers. */    public Observable() {        obs = new Vector();    }    /**     * Adds an observer to the set of observers for this object, provided     * that it is not the same as some observer already in the set.     * The order in which notifications will be delivered to multiple     * observers is not specified. See the class comment.     *     * @param   o   an observer to be added.     * @throws NullPointerException   if the parameter o is null.     */    public synchronized void addObserver(Observer o) {        if (o == null)            throw new NullPointerException();        if (!obs.contains(o)) {            obs.addElement(o);        }    }    /**     * Deletes an observer from the set of observers of this object.     * Passing <CODE>null</CODE> to this method will have no effect.     * @param   o   the observer to be deleted.     */    public synchronized void deleteObserver(Observer o) {        obs.removeElement(o);    }    /**     * If this object has changed, as indicated by the     * <code>hasChanged</code> method, then notify all of its observers     * and then call the <code>clearChanged</code> method to     * indicate that this object has no longer changed.     * <p>     * Each observer has its <code>update</code> method called with two     * arguments: this observable object and <code>null</code>. In other     * words, this method is equivalent to:     * <blockquote><tt>     * notifyObservers(null)</tt></blockquote>     *     * @see     java.util.Observable#clearChanged()     * @see     java.util.Observable#hasChanged()     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)     */    public void notifyObservers() {        notifyObservers(null);    }    /**     * If this object has changed, as indicated by the     * <code>hasChanged</code> method, then notify all of its observers     * and then call the <code>clearChanged</code> method to indicate     * that this object has no longer changed.     * <p>     * Each observer has its <code>update</code> method called with two     * arguments: this observable object and the <code>arg</code> argument.     *     * @param   arg   any object.     * @see     java.util.Observable#clearChanged()     * @see     java.util.Observable#hasChanged()     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)     */    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();    }    /**     * Marks this <tt>Observable</tt> object as having been changed; the     * <tt>hasChanged</tt> method will now return <tt>true</tt>.     */    protected synchronized void setChanged() {        changed = true;    }    /**     * Indicates that this object has no longer changed, or that it has     * already notified all of its observers of its most recent change,     * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.     * This method is called automatically by the     * <code>notifyObservers</code> methods.     *     * @see     java.util.Observable#notifyObservers()     * @see     java.util.Observable#notifyObservers(java.lang.Object)     */    protected synchronized void clearChanged() {        changed = false;    }    /**     * Tests if this object has changed.     *     * @return  <code>true</code> if and only if the <code>setChanged</code>     *          method has been called more recently than the     *          <code>clearChanged</code> method on this object;     *          <code>false</code> otherwise.     * @see     java.util.Observable#clearChanged()     * @see     java.util.Observable#setChanged()     */    public synchronized boolean hasChanged() {        return changed;    }    /**     * Returns the number of observers of this <tt>Observable</tt> object.     *     * @return  the number of observers of this object.     */    public synchronized int countObservers() {        return obs.size();    }}

可以看到jdk自带的观察者模式用起来很方便,当我们需要一个新的主题时,只需要继承Observable类做一些自己需要的扩展即可(如信息的传递是pull还是push),不必重复造轮子。

然而,java.util.Observable类同样存在不好的地方,因为你会发现我们的可观察者Observable竟然tmd是一个类,而不是一个接口,更糟糕的是它竟然没有实现任何一个接口。自己把自己给限制了,毕竟java不支持多重继承,只是单继承的,如果你想拥有另一个超类的行为,显然是不可能的,复用的潜力比较差,当然这并不是说它没有提供有用的功能。

简单说一下jdk Observable设计违反的两个设计原则:
  • 第一种就是上面说的扩展复用问题;
  • 第二种就是Observable竟然将关键的方法保护起来了(可以看到setChanged()方法修饰符是protected类型的),违反了”多用组合,少用继承“原则;
所以,在使用jdk自带的Observable类时,如果你能扩展,那么就可能符合你的需求,否则只能自己写一套观察者模式了。

类似的在jdk中出现观察者模式的地方还有JavaBeans和Swing等。










阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 进门玄关鞋柜 进门见餐厅玄关效果图 玄关柜装修效果图 玄关是指什么地方 没有玄关的进门装修 入户门玄关效果图 正对门玄关效果图 玄关是什么位置 玄关鞋柜样式 房屋玄关装修效果图大全 进门玄关设计 玄关画效果图 进门玄关鞋柜效果图 玄关装修效果图欣赏 鞋柜玄关装修效果图 玄关装修效果图片 玄关鞋柜装修效果图 鞋柜玄关装修效果图进门 室内玄关设计图 玄关隔断装修效果图大全 玄关隔断鞋柜 欧式玄关效果图 欧式装修玄关效果图 玄关放什么植物好 进门没有玄关怎么设计 玄关挂什么画好 办公室玄关设计 新中式入户玄关 玄关放什么好 新中式玄关鞋柜 小户型玄关设计 玄关墙面装饰什么好 入户玄关设计 玄关放鱼缸好吗 进户玄关设计 玄关适合挂什么画 别墅玄关设计效果图 入户玄关设计效果图 玄关放什么画好 玄关设计与装修宜忌 装修隔断玄关图