运维开发网

设计模式大总结(三):观察者模式

运维开发网 https://www.qedev.com 2020-04-07 20:30 出处:网络
前言 因为项目里用到了EventBus,直接就想到了观察者模式。这种模式用的太多了,例如广播的注册,就是典型的观察者模式。 观察者模式最大的好处就是:自己不用时刻关注对方,而是让对方主动通知自己,这样自己省时省力。 举个生活中的例子: 去饭馆吃饭,我点了一个红烧肉盖饭,那我怎么取餐呢? 1、隔一会就去取餐口看一眼。 2、做好了,服务员喊一嗓子,我一听是我点的餐,然后取餐。 很明显第二种更好,这就是

前言

因为项目里用到了EventBus,直接就想到了观察者模式。这种模式用的太多了,例如广播的注册,就是典型的观察者模式。

观察者模式最大的好处就是:自己不用时刻关注对方,而是让对方主动通知自己,这样自己省时省力。

举个生活中的例子:

去饭馆吃饭,我点了一个红烧肉盖饭,那我怎么取餐呢?

1、隔一会就去取餐口看一眼。

2、做好了,服务员喊一嗓子,我一听是我点的餐,然后取餐。

很明显第二种更好,这就是观察者模式。

正文

观察者的概念非常好理解,我画了一个简单的图:

设计模式大总结(三):观察者模式

观察者模式主要有几个步骤:

1、观察者在被观察者 登记注册

2、当观察者发生改变,携带发生改变的信息(Object)通知观察者做相应的处理。

3、观察者自定义处理过程。

其实实现起来也很简单,例如内部有个List,需要通知的时候就遍历一遍:

/** * Created by li.zhipeng on 2017/8/2. * <p> * 完全自定义被观察者 */

public class MyNormalObserable {

    private HashSet<OnObservableListener> observers = new HashSet();

    private static MyNormalObserable instance;

    private MyNormalObserable() {
    }

    public static MyNormalObserable getInstance(){
        if (instance == null){
            instance = new MyNormalObserable();
        }
        return instance;
    }

    /** * 注册观察者 * */
    public void register(OnObservableListener listener){
        observers.add(listener);
    }

    /** * 通知观察者更新 * */
    public void notifyChanged(Object object){
        Iterator<OnObservableListener> iterator = observers.iterator();
        while (iterator.hasNext()){
            iterator.next().update(object);
        }
    }

    /** * 回调的Listener * */
    public interface OnObservableListener{
        void update(Object object);
    }

}

使用的时候,也非常简单

// 注册观察者,传入了要处理变化的逻辑
MyNormalObserable.getInstance().register(new MyNormalObserable.OnObservableListener() {
            @Override
            public void update(Object object) {
                ...
            }
        });

// 通知观察者发生改变
MyNormalObserable.getInstance().notifyChanged(Object);

Android自带的观察者模式

刚才只是一个简单的例子,但是里面还有一些细节需要我们去思考处理,举个例子:

如果我们正在遍历观察者通知改变,这个时候添加观察者或者移除观察者,就会出现问题。

当然还有其他问题,例如多线程等等,所以想要编写一个完善的观察者也不是那么简单,不过不用担心,Android内部已经为我们提供了非常棒的观察者模式辅助类:Observable 和 Observer

Observable:被观察者,提供了通知变化等等的api。

Observer:观察者,需要重写内部的update方法,实现发生变化时的处理。

特别提示:这两个类都在java.util包下,如果你使用了RxJava,RxAndroid,注意类所在的包,别弄混了。

首先继承Observable,修改一点小细节:

/** * Created by li.zhipeng on 2017/8/2. * * 自定义观察者 */

public class MyObservable extends Observable {

    /** * 通知刷新 * */
    public void notifyChanged(){
        notifyChanged(null);
    }

    /** * 通知刷新 * */
    public void notifyChanged(Object object){
        setChanged();
        notifyObservers(object);
    }
}

我们这里定义了notifyChanged方法,为什么要这么做呢?直接notifyObservers不就好了吗?

这么做就说明直接使用notifyObservers肯定不行,因为他有一个判断:

public void notifyObservers(Object arg) {
        // 这是一个临时的数组,一会会用到
        Observer[] arrLocal;
    // 这里加了同步锁,防止多线程操作
        synchronized (this) {
            // 这里做了是否发生改变的判断,是为了防止出现无意义的更新
            if (!hasChanged())
                return;
        // ArrayList转换成一个临时的数组,这样就防止了通知,添加,移除同时发生可能导致的异常
            arrLocal = observers.toArray(new Observer[observers.size()]);
            // 清楚发生变化的状态
            clearChanged();
        }
    // 通知观察者
        for (int i = arrLocal.length-1; i>=0; i--)
            arrLocal[i].update(this, arg);
    }

先要判断是否发生了改变,否则不通知,这也是防止出现无意义的通知,设置改变的方法就是setChanged,notifyObservers本身有clearChanged,所以这里我们把他俩组合了一下,就完成更新的准备工作了。

使用起来还跟平时一样:

// 注册观察者
 register(new Observer() {
     @Override
     public void update(Observable observable, Object o) {
           Log.e("lzp", "update");
      }
});
// 通知更新
observable.notifyChanged();

这两个类的源码非常的简单,有兴趣的可以去看一下,不过我很好奇的是,为什么observable里面用的是ArrayList而不是HashSet,这样防止重复注册不就更简单了吗?

总结

观察者模式就介绍到这里了,可见观察者模式真的是非常方便,这也是EventBus这么火爆的原因,让不同对象之间的通信变得更加简单粗暴。

接下来我们就来写一个EventBus的简易版。

0

精彩评论

暂无评论...
验证码 换一张
取 消