设计模式之——观察者模式

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

首先从一个简单的例子说起,现在的幼儿园、小学老师布置作业,有什么紧急事件或者通知,几乎都会通过一个微信群去通知家长,这个群里包含了所有学生的家长,这真是大大提高了效率,不得不感慨科技的进步带来的便利性,相比我那个时候,连电话都没有的年代,效率真是不可同日而语啊。。。又绕远了,回到正题。这个情景其实就是一个观察者模式。下面通过代码来实现它,看过代码你就会一目了然~

首先看下整体架构设计:(注意:可在新窗口中查看大图)

这里写图片描述

从图中可以看出,抽象主题Subject中提供了三个方法,分别是添加观察者,移除观察者,通知观察者,而Teacher则是具体的主题对象。Observer是所有观察者的抽象,所有观察者都必须实现update()方法,以实现观察者接口。里面的参数则代表具体的需要通知观察者的消息或者内容,当老师需要给家长发送通知的时候,则调用Teacher中的sendMessage方法即可。

下面是整体代码:

package com.example.tb.designpatten.observer.baseinterface;

/**
 * Created by tb on 2017/5/2.
 * 抽象主题
 */

public interface Subject {
    /**
     * 增加一个观察者
     * @param observer
     */
    public void addObserver(Observer observer);

    /**
     * 移除一个观察者
     * @param observer
     */
    public void removeObserver(Observer observer);

    /**
     * 通知所有的观察者
     */
    public void notifyObservers(Object...object);
}
package com.example.tb.designpatten.observer.baseinterface;

/**
 * Created by tb on 2017/5/2.
 * 抽象观察者
 */

public interface Observer {
    public void update(Object...obj);
}
package com.example.tb.designpatten.observer.concretesubject;

import com.example.tb.designpatten.observer.baseinterface.Observer;
import com.example.tb.designpatten.observer.baseinterface.Subject;

import java.util.ArrayList;

/**
 * Created by tb on 2017/5/2.
 * 具体的主题对象(这里就是老师)
 */

public class Teacher implements Subject {
    private ArrayList<Observer> observers;
    public Teacher(){
        observers=new ArrayList<>();
    }
    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        int i=observers.indexOf(observer);
        if(i>=0){
            observers.remove(observer);
        }
    }

    @Override
    public void notifyObservers(Object... object) {
        for (int i = 0; i < observers.size(); i++) {
            observers.get(i).update(object);
        }
    }

    /**
     * 老师发送通知给所有家长
     * @param object
     */
    public void sendMessage(Object...object){
        notifyObservers(object);
    }
}
package com.example.tb.designpatten.observer.concreteobserver;

import android.util.Log;

import com.example.tb.designpatten.observer.baseinterface.Observer;
import com.example.tb.designpatten.observer.baseinterface.Subject;

/**
 * Created by tb on 2017/5/2.
 * 具体的观察者对象(这里就是学生家长0)
 */

public class Parent0 implements Observer {
    private static final String TAG = "Parent0";
    private Subject subject;

    public Parent0(Subject subject){
        this.subject=subject;
        subject.addObserver(this);
    }
    @Override
    public void update(Object... obj) {
        Log.d(TAG, "update: 收到新的通知:"+obj.toString());
    }
}
package com.example.tb.designpatten.observer.concreteobserver;

import android.util.Log;

import com.example.tb.designpatten.observer.baseinterface.Observer;
import com.example.tb.designpatten.observer.baseinterface.Subject;

/**
 * Created by tb on 2017/5/2.
 * 具体的观察者对象(这里就是学生家长1)
 */

public class Parent1 implements Observer {
    private static final String TAG = "Parent1";
    private Subject subject;

    public Parent1(Subject subject){
        this.subject=subject;
        subject.addObserver(this);
    }
    @Override
    public void update(Object... obj) {
        Log.e(TAG, "update: 收到新的通知:"+obj.toString());
    }
}
package com.example.tb.designpatten.observer;

import com.example.tb.designpatten.observer.concreteobserver.Parent0;
import com.example.tb.designpatten.observer.concreteobserver.Parent1;
import com.example.tb.designpatten.observer.concretesubject.Teacher;

/**
 * Created by tb on 2017/5/2.
 */

public class Test {

    public void test(){
        Teacher teacher=new Teacher();
        Parent0 p0=new Parent0(teacher);
        Parent1 p1=new Parent1(teacher);
        teacher.sendMessage("通知:五一国际劳动节放假三天。。。");
    }
}

看完代码是不是脑海里有了整体的认识~观察者模式其实就是定义了对象之间的一对多的依赖关系,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。现实生活中最常见的例子就是报纸订阅服务,以及出版者和订阅者,还有就是现在一些网站支持用户邮箱订阅,当发布新的内容后,会自动推送给订阅用户,说了这么多,你应该有一个大致的了解了吧。。。

观察者模式优缺点分析:

  • 优点
    • 观察者和被观察者之间是抽象耦合,应对业务变化
    • 增强系统灵活性,可扩展性
  • 缺点
    • 在应用观察者模式时需要考虑一下开发效率和运行效率问题,程序中包括一个被观察者、多个观察者、开发和调试等内容会比较复杂,而且在java中消息的通知默认是顺序执行,一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般考虑采用异步的方式。

使用Java内置的观察者模式:其实Java API有内置的观察者模式,就是Observer接口和Observable类,它们都在java.util包下。有了这两个东西,要实现观察者模式就简单多了,因为里面许多功能都已经事先准备好了,看下源码:


package java.util;

public class Observable {
    private boolean changed = false;
    private final ArrayList<Observer> observers;

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

    public Observable() {
        observers = new ArrayList<>();
    }

    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!observers.contains(o)) {
            observers.add(o);
        }
    }

    public synchronized void deleteObserver(Observer o) {
        observers.remove(o);
    }

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

    public void notifyObservers(Object arg) {

        Observer[] arrLocal;

        synchronized (this) {
            if (!hasChanged())
                return;

            arrLocal = observers.toArray(new Observer[observers.size()]);
            clearChanged();
        }

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

    public synchronized void deleteObservers() {
        observers.clear();
    }

    protected synchronized void setChanged() {
        changed = true;
    }

    protected synchronized void clearChanged() {
        changed = false;
    }

    public synchronized boolean hasChanged() {
        return changed;
    }

    public synchronized int countObservers() {
        return observers.size();
    }
}
package java.util;

public interface Observer {

    void update(Observable o, Object arg);
}

怎么样,功能齐全吧,增加,删除,通知观察者都已经实现好功能了,我们直接去继承这个类就可以实现自己的Subject,并且里面设置了一个变量changed来控制是否需要通知观察者,这样就更加灵活的去控制通知的发送情况。但是java.util.Observable也有它的缺陷:

  • 首先它是一个类,而不是一个接口,更糟的是,它甚至没有实现一个接口,你必须去继承它,如果某类想同时具有Observable和另一个超类的行为,就会陷入两难,毕竟Java不支持多重继承,这限制了Observable的复用潜力
  • 再者,因为没有Observable接口,所以你无法建立自己的实现,而里面的setChanged方法也被保护起来了(protected),这意味着,除非你继承Observable,否则你无法创建它的实例并组合到你自己的对象中来,这个设计违反了“多用组合,少用继承”的原则

下面我们再来看看Android源码中观察者模式的应用:首先就是大家很常用的一个控件RecyclerView,而ListView跟它原理差不多,这里我们就分析RecyclerView。它里面最重要的一个功能就是Adapter,通常我们往RecyclerView中添加数据后(这里我们以添加数据来分析),都会调用Adapter的对应的notifyItemInserted方法,而这个方法定义在RecyclerView的内部抽象类Adapter中。

    public static abstract class Adapter<VH extends ViewHolder> {
        //观察者模式中的主题
        private final AdapterDataObservable mObservable = new AdapterDataObservable();

        //代码省略。。。

        public void registerAdapterDataObserver(AdapterDataObserver observer) {
            mObservable.registerObserver(observer);
        }

        public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
            mObservable.unregisterObserver(observer);
        }

        public final void notifyDataSetChanged() {
            mObservable.notifyChanged();
        }

        public final void notifyItemChanged(int position) {
            mObservable.notifyItemRangeChanged(position, 1);
        }

        public final void notifyItemChanged(int position, Object payload) {
            mObservable.notifyItemRangeChanged(position, 1, payload);
        }

        public final void notifyItemRangeChanged(int positionStart, int itemCount) {
            mObservable.notifyItemRangeChanged(positionStart, itemCount);
        }

        public final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
            mObservable.notifyItemRangeChanged(positionStart, itemCount, payload);
        }

        public final void notifyItemInserted(int position) {
            mObservable.notifyItemRangeInserted(position, 1);
        }

        public final void notifyItemMoved(int fromPosition, int toPosition) {
            mObservable.notifyItemMoved(fromPosition, toPosition);
        }

        public final void notifyItemRangeInserted(int positionStart, int itemCount) {
            mObservable.notifyItemRangeInserted(positionStart, itemCount);
        }

        public final void notifyItemRemoved(int position) {
            mObservable.notifyItemRangeRemoved(position, 1);
        }

        public final void notifyItemRangeRemoved(int positionStart, int itemCount) {
            mObservable.notifyItemRangeRemoved(positionStart, itemCount);
        }
    }

一看这个Adapter抽象类就大体有了这么一个认识:观察者模式!那么它是如何运作的?这些观察者又是什么呢?我们一步一步来分析。

我们先到mObservable.notifyItemRangeInserted(positionStart, itemCount);函数中看看:

static class AdapterDataObservable extends Observable<AdapterDataObserver> {
        public boolean hasObservers() {
            return !mObservers.isEmpty();
        }

        public void notifyChanged() {
            // since onChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }

        public void notifyItemRangeChanged(int positionStart, int itemCount) {
            notifyItemRangeChanged(positionStart, itemCount, null);
        }

        public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
            // since onItemRangeChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload);
            }
        }

        public void notifyItemRangeInserted(int positionStart, int itemCount) {
            // since onItemRangeInserted() is implemented by the app, it could do anything,
            // including removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onItemRangeInserted(positionStart, itemCount);
            }
        }

        public void notifyItemRangeRemoved(int positionStart, int itemCount) {
            // since onItemRangeRemoved() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onItemRangeRemoved(positionStart, itemCount);
            }
        }

        public void notifyItemMoved(int fromPosition, int toPosition) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onItemRangeMoved(fromPosition, toPosition, 1);
            }
        }
    }

这个代码很简单,最终调用是在30行这个函数,里面遍历所有观察者,并且调用它们的onItemRangeInserted方法,从而告知观察者发生了变化,也就是添加了数据。

那么这些观察者是从那里来的呢?其实这些观察者就是RecyclerView通过setAdapter方法设置Adapter产生的,我们看看相关代码:

    public void setAdapter(Adapter adapter) {
        // bail out if layout is frozen
        setLayoutFrozen(false);
        setAdapterInternal(adapter, false, true);
        requestLayout();
    }

    private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
            boolean removeAndRecycleViews) {
        if (mAdapter != null) {
            mAdapter.unregisterAdapterDataObserver(mObserver);
            mAdapter.onDetachedFromRecyclerView(this);
        }
            // 代码省略。。。

        if (adapter != null) {
            adapter.registerAdapterDataObserver(mObserver);
            adapter.onAttachedToRecyclerView(this);
        }
        //代码省略。。。
    }

从程序中可以看到,在设置adapter时,去注册了这个观察者,而它的创建是在定义的时候:

    private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();

这样我们的主题,观察者都有了,这个时候你就可能有点不明白,RecyclerViewDataObserver是什么?它是如何运作的?那么就先来看看这个类,它同样也是定义在RecyclerView的一个内部类,代码如下:

private class RecyclerViewDataObserver extends AdapterDataObserver {
        @Override
        public void onChanged() {
            assertNotInLayoutOrScroll(null);
            if (mAdapter.hasStableIds()) {
                // TODO Determine what actually changed.
                // This is more important to implement now since this callback will disable all
                // animations because we cannot rely on positions.
                mState.mStructureChanged = true;
                setDataSetChangedAfterLayout();
            } else {
                mState.mStructureChanged = true;
                setDataSetChangedAfterLayout();
            }
            if (!mAdapterHelper.hasPendingUpdates()) {
                requestLayout();
            }
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
            assertNotInLayoutOrScroll(null);
            if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
                triggerUpdateProcessor();
            }
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            assertNotInLayoutOrScroll(null);
            if (mAdapterHelper.onItemRangeInserted(positionStart, itemCount)) {
                triggerUpdateProcessor();
            }
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            assertNotInLayoutOrScroll(null);
            if (mAdapterHelper.onItemRangeRemoved(positionStart, itemCount)) {
                triggerUpdateProcessor();
            }
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            assertNotInLayoutOrScroll(null);
            if (mAdapterHelper.onItemRangeMoved(fromPosition, toPosition, itemCount)) {
                triggerUpdateProcessor();
            }
        }

        void triggerUpdateProcessor() {
            if (mPostUpdatesOnAnimation && mHasFixedSize && mIsAttached) {
                ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
            } else {
                mAdapterUpdateDuringMeasure = true;
                //重新布局
                requestLayout();
            }
        }
    }

看这两个函数:onItemRangeInserted,triggerUpdateProcessor。一切是不是都清楚了。
当RecyclerView添加数据(删除,修改)时,调用Adapter的对应的notify等方法(notifyItemMoved,notifyItemChanged,notifyDataSetChanged,notifyItemRemoved…),这个对应的函数又会调用AdapterDataObservable的对应的notify等函数,这个函数会调用所有观察者的onItemChange方法,在这个函数中又会调用RecyclerView重新布局的函数使得界面刷新,这就是一个观察者模式!

BroadcastReceiver是Android的四大组件之一,它作为应用内、进程间的一种重要通信手段,能够将某个消息通过广播的形式传递给它注册的对应广播接收器的对象,接收对象需要通过Context的registerReceiver函数注册到AMS中,当通过sendBroadcast发送广播时,所有注册了对应的IntentFilter的BroadcastReceiver对象就会收到这个消息,BroadcastReceiver的onReceiver方法就会被调用,这就是一个典型的发布——订阅模式,也就是我们的观察者模式,模式真是无处不在啊,也让我们感叹Android源码的优秀魅力,感兴趣的童鞋可以自己查阅源码进行分析。

通过上面的讲解,相信大家应该对观察者模式有了自己的认识。最后,有不懂的童鞋可以在下面留言~

源码下载

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值