观察者模式

一 定义

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

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

二 模式结构

角色介绍:

  • 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 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 Observable object's
     * notifyObservers method to have all the object's
     * observers notified of the change.
     *
     * @param   o     the observable object.
     * @param   arg   an argument passed to the notifyObservers
     *                 method.
     */
    void update(Observable o, Object arg);
}

  • 被观察者Observable,可以看到,Observable源码也是实现了addObserver,deleteObserver,notifyObservers等方法。
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 null 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
     * hasChanged method, then notify all of its observers
     * and then call the clearChanged method to
     * indicate that this object has no longer changed.
     * 

* Each observer has its update method called with two * arguments: this observable object and null. In other * words, this method is equivalent to: *

* notifyObservers(null)
* * @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 * hasChanged method, then notify all of its observers * and then call the clearChanged method to indicate * that this object has no longer changed. *

* Each observer has its update method called with two * arguments: this observable object and the arg 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 Observable object as having been changed; the * hasChanged method will now return true. */ 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 hasChanged method will now return false. * This method is called automatically by the * notifyObservers 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 true if and only if the setChanged * method has been called more recently than the * clearChanged method on this object; * false otherwise. * @see java.util.Observable#clearChanged() * @see java.util.Observable#setChanged() */ public synchronized boolean hasChanged() { return changed; } /** * Returns the number of observers of this Observable 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("新技术来袭!");
  • 运行结果


四 优缺点

优点:

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

五 使用场景

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

你可能感兴趣的:(观察者模式)