java设计模式--观察者模式

观察者模式是一种使用效率非常高的模式,我们在源码中也可以初创看到他的身影,如在我们经常使用的listview中的adapter的notifydatasetchanged方法就是观察者模式的一种实现方法,以及现在非常流行的RxJava中的实现过程也是基于这种模式的,下面来学习一下观察者模式。


定义

观察这模式是定义对象间一种一对多的依赖关系,使得每当一个状态改变时,所有依赖与他的对象都会得到通知,并且得到相应的改变,在观察者模式中,主要有两个名字定义:观察者和被观察者,当被观察者的状态发生改变时,观察者会得到通知并且进行相对应的行为变化。

举个例子:被观察者好比技术总监,而观察者就像程序猿一样(= ̄ω ̄=),当总监得到相关任务后,会发送一个邮件给程序猿,程序猿根据这封邮件进行相关的工作,在这两者之间,通信的媒介在于邮件,在代码中相对应于一种接口回调的思想。


使用场景

  1. 关联行为场景,需要注意的是,关联行为是可以拆分的,而不是组合的关系
  2. 事件多级触发场景
  3. 跨系统的消息交换场景,如消息队列,ADIL之间的观察者模式,以及事件总线的处理(EventBus)机制。

观察者模式的UML图

这里写图片描述

Subject:只是一个抽象主题类,相当于被观察者的角色,它把所有的观察者对象的引用保存在一个集合里,每个主题可以拥有任意数量的观察者,抽象主题提供一个接口,可以增加或者删除对象。

ConcreteObject:具体的被观察者的实现类,该角色将有关状态存入具体观察者对象,在其内部的状态发生改变时候,发送消息给所有观察者。

Observer:抽象观察者,它定义一个更新接口,是的在得到主题更改的通知后更新自己

ConcreteObserver:具体观察者实现类,该角色实现抽象观察者所定义的更新接口,以便在主题发生改变时更新自己的状态。


简单实现


//定义一个被观察者接口
public interface MyObservser {
    void register(MyListenser listenser);
    void unregister(MyListenser listenser);

}

------
//总监实现类,即被观察者具体实现
public class ZongJian implements MyObservser {
    private List<MyListenser> list=new ArrayList<>();
    @Override
    public void register(MyListenser listenser) {
        if (!list.contains(listenser)) {
            list.add(listenser);
        }

    }

    @Override
    public void unregister(MyListenser listenser) {
        if (list.contains(listenser)) {
            list.remove(listenser);
        }

    }

    public void setData(String string){
        System.out.println("总监发布任务:"+string);
        for(int i=0;i<list.size();i++){
            list.get(i).getData(string);
        }
    }

}

-----
//观察者接口
public interface MyListenser {
        void getData(String str);
}

----
//程序猿具体实现类
public class ChengXuYuan {
    private MyListenser listenser;

    public void setListener(MyListenser listenser){
        this.listenser=listenser;
    }

    public MyListenser getListener(){
        return listenser;
    }

}
-----
public class Main {
    public static void main(String[] args) {
        ZongJian observser=new ZongJian();
        ChengXuYuan chengXuYuan=new ChengXuYuan();
        chengXuYuan.setListener(new MyListenser() {

            @Override
            public void getData(String str) {
                System.out.println("程序猿1要开始工作了,任务是:"+str);

            }
        });
        ChengXuYuan chengXuYuan2=new ChengXuYuan();
        chengXuYuan2.setListener(new MyListenser() {

            @Override
            public void getData(String str) {
                System.out.println("程序猿2要开始工作了,任务是:"+str);

            }
        });
        observser.register(chengXuYuan.getListener());
        observser.register(chengXuYuan2.getListener());
        observser.setData("总监我给的任务是:没有蛀牙!");
    }
}

结果如下图所示:

这里写图片描述

可以看到,当总监发出任务后,程序猿们都可以接受到这个消息,我们就完成了一个简单的观察者模式的实现。


notifyDataChange源码分析

下面我们来研究研究adapter中的notifyDataChange的实现过程,首先我们看看Adapter这个接口,所有的adapter子类都需要实现这个接口,在adapter源码中,有两个如下的方法:

/**
     * Register an observer that is called when changes happen to the data used by this adapter.
     *
     * @param observer the object that gets notified when the data set changes.
     */
    void registerDataSetObserver(DataSetObserver observer);

    /**
     * Unregister an observer that has previously been registered with this
     * adapter via {@link #registerDataSetObserver}.
     *
     * @param observer the object to unregister.
     */
    void unregisterDataSetObserver(DataSetObserver observer);

    /**
     * How many items are in the data set represented by this Adapter.
     * 
     * @return Count of items.
     */

我们可以看到,这就是相当于我们上面讲的被观察者注册与取消注册接口的过程,我们在点到BaseAdapter中,查看代码如下:

 private final DataSetObservable mDataSetObservable = new DataSetObservable();

    public boolean hasStableIds() {
        return false;
    }

    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }

    /**
     * Notifies the attached observers that the underlying data has been changed
     * and any View reflecting the data set should refresh itself.
     */
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

    /**
     * Notifies the attached observers that the underlying data is no longer valid
     * or available. Once invoked this adapter is no longer valid and should
     * not report further data set changes.
     */
    public void notifyDataSetInvalidated() {
        mDataSetObservable.notifyInvalidated();
    }

DataSetObservable是被观察者模型,BaseAdapter中notifyDataSetChanged在实质上是调用了mDataSetObservable.notifyChanged()方法,继续点进去,我们看看DataSetObservable这个类,发现他是继承于Observable这个官方接口的,此官方接口主要提供我们简单实现观察者模式,简化我们要书写的代码量的过程,与之相对应的就是Observer接口,notifyChange方法:

public void notifyChanged() {
        synchronized(mObservers) {
            // 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();
            }
        }
    }

看到最终会调用观察者的onChange方法,那这个观察者到底是谁呢?就是DataSetObserver,那么这两个值到底是什么时候会被赋值的呢,这就要看listView中的setAdapter实现过程了:

 public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();

        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;
        }

        mOldSelectedPosition = INVALID_POSITION;
        mOldSelectedRowId = INVALID_ROW_ID;

        // AbsListView#setAdapter will update choice mode states.
        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();

            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);

            mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());

            int position;
            if (mStackFromBottom) {
                position = lookForSelectablePosition(mItemCount - 1, false);
            } else {
                position = lookForSelectablePosition(0, true);
            }
            setSelectedPositionInt(position);
            setNextSelectedPositionInt(position);

            if (mItemCount == 0) {
                // Nothing selected
                checkSelectionChanged();
            }
        } else {
            mAreAllItemsSelectable = true;
            checkFocus();
            // Nothing selected
            checkSelectionChanged();
        }

        requestLayout();
    }

我们可以看到:

 mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);

由于源码不允许继续跟进,所以这里进行一个猜测Listview中进行了观察者与被观察者数据的整合,最终实现了当我们更新数据的时候实现了视图上面的更新操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值