观察者模式

作者: Jackson杰 | 来源:发表于2019-05-28 09:44 被阅读17次

    一 定义

    观察者模式也叫做发布订阅模式,是一种使用率非常高的设计模式。

    定义:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

    二 模式结构

    角色介绍:

    • Subject:抽象主题,也就是被观察者的角色,抽象主题角色把所有观察者对象的引用保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
    • ConcreteSubject:具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过得观察者发送通知,具体主题角色又被叫做具体观察者角色。
    • Observer:抽象观察者,该角色是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
    • ConcreteObserver:具体观察者,该角色实现抽象观察者角色所定义的更新接口,以便在主题的状态发生变化时更新自身的状态。

    三 实例

    观察者模式的通用代码如下:

    • 抽象观察者Observer接口,主要完成在收到通知后更新自己。
    public interface Observer {
    
        // 更新方法
         void update();
    }
    
    • 具体的观察者ConcreteObserver,实现抽象观察者中定义的接口,在收到通知后更新自己。
    public class ConcreteObserver implements Observer {
        @Override
        public void update() {
            System.out.println("接收到更新通知,更新!");
        }
    }
    
    • 被观察者角色Subject,主要是定义了一个被观察者数组,实现注册,移除观察者,通知观察者更新等。
    public abstract class Subject {
    
        // 定义一个观察者数组
        private List<Observer> mObservers=new ArrayList<>();
    
        /**
         * 注册观察者对象
         * @param o
         */
        public void addObserver(Observer o){
            this.mObservers.add(o);
        }
    
    
        /**
         * 移除观察者对象
         * @param o
         */
        public void deleteObserver(Observer o){
            this.mObservers.remove(o);
        }
    
    
        /**
         * 通知所有观察者更新
         */
        public void notifyObserver(){
            for (Observer observer:mObservers){
                observer.update();
            }
         }
    }
    
    • 具体的被观察者ConcreteObserver,实现自己的业务逻辑。
    public class ConcreteSubject extends Subject{
    
        /**
         * 具体的业务逻辑
         */
        public void doSomething(){
            super.notifyObserver();
        }
    }
    
    • 测试代码
    // 创建一个被观察者
            ConcreteSubject subject=new ConcreteSubject();
            // 定义一个观察者
            Observer observer=new ConcreteObserver();
            // 注册观察者
            subject.addObserver(observer);
            // 开始观察
            subject.doSomething();
    

    具体结果就不贴了,注册观察者后,被观察者会发送通知,通知到观察者,观察者收到通知后,更新自己。

    下面,我们以订阅开发者论坛的技术文章为例,Android 开发者网站是google专门向android开发者提供技术支持的专业社区,开发者可以通过邮件订阅的方式订阅上面的文章。在这里,开发者相当于观察者,Android 开发者网站相当于被观察者。

    实际上,针对观察者模式,Java向我们提供了观察者和被观察对象,在Java的实用工具类库java.util包下,我们可以直接使用,下面可以看下源码。

    • 观察者Observer接口,主要定义了一个可用于数据更新的接口。
    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);
    }
    
    
    • 被观察者Observable,可以看到,Observable源码也是实现了addObserver,deleteObserver,notifyObservers等方法。
    public class Observable {
        private boolean changed = false;
        private Vector<Observer> 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
                 */
                // Android-changed: Call out to hasChanged() to figure out if something changes.
                // Upstream code avoids calling the nonfinal hasChanged() from the synchronized block,
                // but that would break compatibility for apps that override that method.
                // if (!changed)
                if (!hasChanged())
                    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();
        }
    }
    
    

    以下是具体的代码:

    • 观察者角色,观察者实现了Observer接口,只要实现一个update()方法就能接受到更新。
    public class Developer implements Observer {
    
        private String name;
    
        public Developer(String name){
            this.name=name;
        }
    
        @Override
        public void update(Observable o, Object arg) {
            System.out.println("你好,"+name+",Android开发网站更新啦,内容:"+arg);
        }
    }
    
    • 被观察者角色,实现Observable,在这里可以实现自己的业务逻辑,本实例实现了一个发布新技术的方法。
    public class DevelopTribune extends Observable {
    
        // 自己的业务逻辑
        public void postNewPublish(String content){
            // 标识状态发生改变
            setChanged();
            // 通知所有观察者
            notifyObservers(content);
        }
    }
    
    • 测试代码
    // 被观察者
           DevelopTribune developTribune=new DevelopTribune();
           // 观察者
           Developer developer1=new Developer("Lucy");
           Developer developer2=new Developer("James");
           Developer developer3=new Developer("Jackson");
           // 注册观察者
           developTribune.addObserver(developer1);
           developTribune.addObserver(developer2);
           developTribune.addObserver(developer3);
    
           // 发布更新
           developTribune.postNewPublish("新技术来袭!");
    
    • 运行结果


    四 优缺点

    优点:

    • 观察者和被观察者之间是抽象耦合,应对业务变化,非常容易扩展。
    • 增强系统灵活性,可扩展性。
      缺点:
      在运用观察者模式需要考虑效率问题,即存在一个被观察者和多个观察者的时候,开发和调试会比较复杂,如果一个观察者卡壳,会影响整体的执行效率。

    五 使用场景

    • 关联行为场景,关联行为要是可拆分的,而不是组合关系。
    • 事件多级触发场景
    • 跨系统信息交换场景

    相关文章

      网友评论

        本文标题:观察者模式

        本文链接:https://www.haomeiwen.com/subject/bhrctctx.html