zoukankan      html  css  js  c++  java
  • 观察者模式

    观察者模式

    一、简介

    观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。该模式一个重要作用就是解耦,将被观察者和观察者进行解耦,使他们之间的依赖性更小

    二、使用场景

    • 关联行为场景,需要注意的是关联行为是可拆分的而不是“组合”关系
    • 事件多级触发场景
    • 跨系统的消息交换场景,如消息队列、事件总线的处理机制

    三、简单实现

    这里我们以微信公众号的订阅为例。公众号当其更新内容时就会推送给订阅了该公众号的读者。

        //被观察者
        public class Wechat extends Observable{
            public void postNewPublication(String content){
                setChanged();
                notifyObservers(content);
            }
        }
    
        //观察者
        public class Reader implements Observer{
           public String name ;
    
            public Reader(String name) {
                this.name = name;
            }
    
            @Override
            public void update(Observable o, Object arg) {
                Log.i(TAG, "update: wechat is update content is :"+arg);
            }
        }
        
        public void test(){
            Wechat wechat=new Wechat();
            
            Reader reader1=new Reader("reader1");
            Reader reader2=new Reader("reader2");
            Reader reader3=new Reader("reader3");
            
            wechat.addObserver(reader1);
            wechat.addObserver(reader2);
            wechat.addObserver(reader3);
            
            wechat.postNewPublication("up up up");
        }
    

    这里需要注意的是Observer和Observable是JDK内置的类,表示观察者和被观察者。

    四、观察者模式在Android中应用

    ListView和RecycleView 的notifyDataSetChanged

    当我们在使用ListView或RecycleView时如果数据发生变化我们会调用Adapter的notifyDataSetChanged()方法,如下所示

     public void notifyDataSetChanged() {
            mDataSetObservable.notifyChanged();
        }
    

    在方法内部调用了mDataSetObservable.notifyChanged,这里的mDataSetObservable是一个DataSetObservable实例

        private final DataSetObservable mDataSetObservable = new DataSetObservable();
    

    而DataSetObservable继承自Observable,我们看下DataSetObservable的notifyChanged方法

    public class DataSetObservable extends Observable<DataSetObserver> {
    
    public void notifyChanged() {
            synchronized(mObservers) {
                for (int i = mObservers.size() - 1; i >= 0; i--) {
                    mObservers.get(i).onChanged();
                }
            }
        }
     }
    

    可以看到调用了DataSetObserver的onChanged方法,DataSetObserver是一个抽类这里mObservers.get(i)获得的是其子类AdapterDataSetObserver.

    class AdapterDataSetObserver extends DataSetObserver {
            private Parcelable mInstanceState = null;
            @Override
            public void onChanged() {
                mDataChanged = true;
                mOldItemCount = mItemCount;
                mItemCount = getAdapter().getCount();
                if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                        && mOldItemCount == 0 && mItemCount > 0) {
                    AdapterView.this.onRestoreInstanceState(mInstanceState);
                    mInstanceState = null;
                } else {
                    rememberSyncState();
                }
                checkFocus();
                //重新布局
                requestLayout();
            }
    
            ...
    
            public void clearSavedState() {
                mInstanceState = null;
            }
     }
    

    可以看到在AdapterDataSetObserver的onChanged方法中调用了requestLayout来进行重新布局。

    BroadcastReceiver

    在Android中广播也是基于观察者模式的

    五、小结

    观察者模式优点:

    • 解耦观察者与被观察者,应对业务变化
    • 增强系统灵活性、可扩展性

    缺点:

    • 在使用时要考虑开发效率和运行效率,程序中包括一个被观察者、多个观察者、开发调试等内容会比较复杂,且Java中消息通知默认是顺序执行,如果一个观察者卡顿,那么会影响整体执行效率,在这种情况下一般考虑使用异步的方式。
  • 相关阅读:
    洛谷P1948 [USACO08JAN]电话线Telephone Lines
    bzoj4152 [AMPPZ2014]The Captain
    洛谷P1396 营救
    洛谷P1821 [USACO07FEB]银牛派对Silver Cow Party
    洛谷P2002 消息扩散
    Uoj308【UNR #2】UOJ拯救计划
    洛谷P1937 [USACO10MAR]仓配置Barn Allocation
    洛谷P3740 [HAOI2014]贴海报
    洛谷P2344 奶牛抗议
    Android(java)学习笔记124:利用Service在后台播放背景音乐
  • 原文地址:https://www.cnblogs.com/Robin132929/p/13804786.html
Copyright © 2011-2022 走看看