设计模式-观察者模式

Posted 双木青橙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-观察者模式相关的知识,希望对你有一定的参考价值。

1.定义

1.1抽象定义

  • 报社的业务是出版报纸
  • 向某家报社订阅报纸,只要他们有新报纸出版,就会向你送来,要是你是他们的订户,你就会一直收到他们的报纸。
  • 当你不想再看报纸的时候,取消订阅,他们就会不再送报纸来。
    相当于出版者+订阅者= 观察者模式,出版者改为为“主题”(subject),订阅者改称为“观察者”(Observer)。

1.2 标准定义

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都你会收到通知并自动更新。
观察者模式定义了一系列对象之间的一对多关系。当一个对象改变状态,其他依赖者都会收到通知。

1.3 观察者模式如何实现松耦合

当两个对象之间松耦合,它他们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象设计。让主题和观察者之间松耦合。
关于观察者的一切,主题只知道观察者实现了某个接口(也就是Oberserver接口)。主题不需要知道观察者的具体类是谁,做了些什么或者其他任何细节。
任何时候我们都可以增加新的观察者。因为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者,主题不会受到任何影响。同时的,也可以在任何时候删除某些观察者。
有新类型的观察者出现时,主题的代码不需要修改。假如我们有个新的具体类需要当观察者,我们不需要为了兼容新类型而修改主题的代码,所有要做的就是在新的类里实现此观察者接口,然后注册为观察者即可。主题不在乎别的,它只会发送通知给所有实现了此观察者接口的对象。
我们可以解决一下地复用主题或者观察者。如果我们在其他地方需要使用主题或者观察者。可以轻易复用,因为二者并非紧耦合。
改变主题或者观察者其中一方,并不会影响另一方。因为两者是松耦合,所以只要是他们之间的接口仍被遵守,我们就可以自由地改变他们。
松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低

Observer接口与Observable类

Observer接口和Observable类是Java API内置的观察者模式,Observer是观察者,Observable是主题(subject)。值得注意的是:Observable并不是一个接口,而一个Java类。(当并不是一个好的方式,Java语言只允许继承一个父类,在大型项目中还是自己新建ObserverManager管理类或者实现一个接口来实现观察者模式。)

  • Observable-主题类
/**
* 主题类
*/
public class Observable 
    private boolean changed = false;
    private Vector<Observer> 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);
    

    /**
     * 当主题改变后(或者你想用通知观察者们)时,你一般会通过hasChanged标记主题已改变,然后通过此方法通知所有观察者,然后再通过
     * clearChanged标记主题不再改变,直到下一次想要通知
     * 此方法不带arg参数
     */
    public void notifyObservers() 
        notifyObservers(null);
    

    /**
     * 见notifyObservers(null)方法
     * 每个观察者的update方法被传入当前主题对象和arg参数依次调用
     * @param   arg   Object类型,任意要传递给观察者参数
     */
    public void notifyObservers(Object arg) 
        Object[] arrLocal;

        synchronized (this) 
            /* 这是一个被synchronized 注解的同步方法块,用于同步获取最新的观察者列表。但是通知这些观察者实际上并不是同步的
             * (不影响功能且有效避免阻塞)
             * 最坏的情况是:
             * (无论是否使用synchronized都可能存在这个问题,加了synchronized可以有效避免在实际通知过程中观察者被随意进出)
             * 1)一个新添加的观察者会错过通知当通知已经在进步中时
             * 2)一个刚解注册的观察者会被错误通知。
             */
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    

    /**
     * 清除所有观察者
     */
    public synchronized void deleteObservers() 
        obs.removeAllElements();
    

    /**
     * 标记当前主题已经改变,注意,此方法一定要在调用notifyObservers之前
     */
    protected synchronized void setChanged() 
        changed = true;
    

    /**
     * 清理主题Changed清理标记,常用于已经通知观察者后处理
     */
    protected synchronized void clearChanged() 
        changed = false;
    

    /**
     * 获取当前主题是否已改变标记
     */
    public synchronized boolean hasChanged() 
        return changed;
    

    /**
     * 获取观察者数量
     */
    public synchronized int countObservers() 
        return obs.size();
    

  • Observer接口-观察者
/**
 * 一个类可以通过实现Observer接口,当它想被观察对象(主题)变化实时通知时。
 */
public interface Observer 
    /**
     * 主题变化时,会调用notifyObservers通知观察者们,update方法在此时被调用
     *
     * @param   o 主题
     * @param   arg   notifyObservers传递过来的参数
     */
    void update(Observable o, Object arg);

以上是关于设计模式-观察者模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式-观察者模式

设计模式-观察者模式

设计模式-观察者模式

Head First Design Patten观察者模式

Head First Design Patten观察者模式

java 观察者模式