Design Pattern 之 观察者模式

Posted 月盡天明

tags:

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

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/51815880


观察者模式介绍

观察者模式 又称为 发布-订阅模式 。定义了一种一对多的依赖关系,当被观察者对象状态发生改变时,通知所有依赖于它(订阅它)的观察者对象。

RSS订阅 邮件订阅 大家应该都知道,你订阅后,将会及时获得所订阅的相关最新内容。所有订阅该内容的“订阅者”,当该内容有更新时,就可以收到通知。这就是一种观察者模式的应用场景。


UML图

java中,内置了ObserverObservable,分别表示抽象的观察者对象和抽象主题角色(可被观察,被观察者)。

这里写图片描述

Observer是一个借口,定义了一个update方法。

public interface Observer {
    void update(Observable o, Object arg);
}

观察者模式应用

先来看看JDK中Observer和Observable的源码。

Observer

public interface Observer {
    /**
     * 更新操作
     */
    void update(Observable o, Object arg);
}

该类是一个 接口 ,只有一个更新的函数。

Observable


package java.util;

/**
 * 表示一个可被观察的对象
 * 一个被观察者可以有多个观察者对象
 * 调用 notifyObservers 方法可以通知所有的观察者调用他们的 update 方法
 * 当一个被观察者被初始创建的时候,它的观察者set集合是空的
 */
public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs; // 通过向量保存观察者对象

    /** Construct an Observable with zero Observers. */

    public Observable() {
        obs = new Vector<>();
    }

    /**
     * 添加一个观察者对象
     * 
     * @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);
        }
    }

    /**
     * 删除一个观察者对象
     * 
     * @param   o   the observer to be deleted.
     */
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    /**
     * 当对象发生变化是,首先调用hasChanged表明发生了改变,然后通知所有的观察者对象,调用它们各自的update方法,最后调用clearChanged方法表明当前对象已经没有改变了。
     * 每个观察者对象都有它的update方法,该方法有两个参数
     *
     * @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);
    }

    /**
     * arg参数最终会赋值给update函数的第二个参数
     * 
     * @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) {

        Object[] arrLocal;

        synchronized (this) {
            //由此可以看书,如果没有changed == false,直接return,后序代码不执行。
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        //倒序遍历观察者对象数组,调用update方法。由此看出,后添加进来的观察者对象会被先调用update方法。
        for (int i = arrLocal.length-1; i>=0; i--) 
            ((Observer)arrLocal[i]).update(this, arg);
    }

    /**
     * 清楚所有的观察者对象
     */
    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }

    /**
     * 设置改变标志,只有调用了该方法,观察者对象才能被通知。
     */
    protected synchronized void setChanged() {
        changed = true;
    }

    /**
     * 重置改变标志
     *
     * @see     java.util.Observable#notifyObservers()
     * @see     java.util.Observable#notifyObservers(java.lang.Object)
     */
    protected synchronized void clearChanged() {
        changed = false;
    }

    /**
     * 判断是否有改变
     * 
     * @see     java.util.Observable#clearChanged()
     * @see     java.util.Observable#setChanged()
     */
    public synchronized boolean hasChanged() {
        return changed;
    }

    /**
     * 返回观察者对象的数量
     */
    public synchronized int countObservers() {
        return obs.size();
    }
}

基本应用

/**
 * 被观察者类 继承Observable类,表示这个类可以被观察。
 * 
 * @author Admin
 * 
 */
public class SimpleObservable extends Observable {
    private int data = 0;

    public int getData() {
        return data;
    }

    public void setData(int data) {
        if (this.data != data) {
            this.data = data;
            // 标志状态改变,一定要调用函数notify方法才有效
            setChanged();
            // 通知所有观察者
            notifyObservers("abc");
        }
    }

}
/**
 * 观察者1号
 * 
 * @author Admin
 * 
 */
public class SimpleObserver implements Observer {

    public SimpleObserver(SimpleObservable simpleObservable) {
        simpleObservable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("SimpleObserver: " + ((SimpleObservable) o).getData() + " -- " + (String)arg);
    }
}
/**
 * 观察者2号
 * @author Admin
 *
 */
public class OtherObserver implements Observer{

    public OtherObserver(SimpleObservable observable){
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("OtherObserver: " + ((SimpleObservable)o).getData() + " -- " + (String)arg);
    }
}
public class SimpleTest {
    public static void main(String[] args) {
        SimpleObservable observable = new SimpleObservable();

        new OtherObserver(observable);
        new SimpleObserver(observable);

        observable.setData(1);
        observable.setData(2);
        observable.setData(2);
        observable.setData(4);
    }
}

测试的结果如下:

SimpleObserver: 1 -- abc
OtherObserver: 1 -- abc
SimpleObserver: 2 -- abc
OtherObserver: 2 -- abc
SimpleObserver: 4 -- abc
OtherObserver: 4 -- abc

异步观察者模式

上面介绍的都是同步观察者模式。同步观察者模式会有阻塞问题。各个观察者按照顺序执行update方法。一旦有一个observer比较耗时的话,后序的observer也得等着。

异步观察者模式就不一样,不会有这样的阻塞问题。

针对update方法做文章

/**
 * 异步观察模式的观察者接口
 */
public interface AsyncObserver {

    /**
     * 
     * @param o
     * @param arg
     */
    void update(AsyncObservable o, Object arg);

}
/**
 * 异步观察者模式的被观察者对象
 */
public class AsyncObservable {

    private boolean changed = false;
    private Vector<Wrapper> obs;

    public AsyncObservable() {
        obs = new Vector<>();
    }

    /**
     * 
     * @param wrapper
     */
    public synchronized void addObserver(AsyncObserver o) {
        if (o == null)
            throw new NullPointerException();
        Wrapper wrapper = new Wrapper(o);
        if (!obs.contains(wrapper)) {
            obs.addElement(wrapper);
        }
    }

    /**
     * 
     */
    public synchronized void deleteObserver(AsyncObserver o) {
        Iterator<Wrapper> iterator = obs.iterator();
        while (iterator.hasNext()) {
            Wrapper wrapper = iterator.next();
            if (wrapper.getAsyncObserver() == o) {
                obs.remove(wrapper);
                break;
            }
        }
    }

    /**
     * 
     */
    public void notifyObservers() {
        notifyObservers(null);
    }

    /**
     * 
     */
    public void notifyObservers(Object arg) {

        Object[] arrLocal;

        synchronized (this) {

            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

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

    /**
     * 
     */
    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();
    }

}
/**
 * 观察者的包装类 
 */
public class Wrapper {

    private AsyncObserver observer;

    public Wrapper(AsyncObserver o) {
        this.observer = o;
    }

    public AsyncObserver getAsyncObserver() {
        return observer;
    }

    /**
     * 
     * @param observable
     * @param o
     */
    public void update(AsyncObservable observable, Object o) {
        new Handler(observable, o).start();
    }

    class Handler extends Thread {

        AsyncObservable observable;
        Object object;

        public Handler(AsyncObservable observable, Object o) {
            this.observable = observable;
            this.object = o;
        }

        @Override
        public void run() {
            observer.update(observable, object);
        }
    }
}

最主要的就是这个Wrapper包装类。被观察者的notify方法内部实际上调用的是Wrapper类中的update()方法。

将每个update操作放到一个线程中去。这样多个线程“同时”工作。

这样即是某些观察者类的update做一些耗时操作,也不影响其他观察者类的update的工作、


测试结果:

hahahaha
hahahaha
hahahaha
hahahaha
hahahaha
hahahaha
hahahaha
hahahaha
hahahaha
ObserverB -- i think jingjing -- jingjing
hahahaha
ObserverC -- i think jingjing -- jingjing
ObserverA -- i think jingjing -- jingjing

总结

观察者模式中,被观察者与观察者通过接口进行联系。被观察者只知道一个观察者列表,列表中的每个对象都是一个抽象观察者接口。

android中观察者模式的应用场景有:

  • 广播机制

  • ListView数据更改

  • 点击事件

  • ContentObserver


完毕。

:-D

晚安~

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

Refresh design pattern

pattern设计模式 - Observer观察者模式

设计模式之观察者模式(php实现)

Java学习笔记——设计模式之十.观察者模式

设计模式之- 观察者模式(Observer Pattern)

秒懂设计模式之观察者模式(Observer Pattern)