美文网首页
设计模式之观察者模式

设计模式之观察者模式

作者: BrightLight | 来源:发表于2019-02-25 23:17 被阅读0次

    一、什么叫观察者?

    先理解一个简单的例子:很多购房者都在关注房子的价格变化,每当房子的价格变化时,所有购房者都可以观察得到,实际上购房者都属于观察者。

    • 观察者模式的定义:定义对象间一种一对多的依赖关系,使得每当一个对象发生改变,则所有依赖她的对象都会等到通知并被自动更新。
    • 使用场景:1、 关联行为场景;2、事件多级触发场景;3、跨系统的消息交互场景,如消息队列、事件总线的处理机制

    二、观察者模式实现

    在Java.util包中提供了Observable和Observer接口,使用它们即可完成观察者模式。
    Observable:需要被观察的类必须继承Observable类。Observable类的常用方法有:

    • 1、public void addObserver(Observer o) : 添加一个观察者;
    • 2、public void deleteObserver(Observer o):删除一个观察者;
    • 3、public void setChanged() ; 被观察者状态发生改变;
    • 4、public void notifyObservers(Object args) ; 通知所有观察者状态改变;

    Observer:每个观察者都需要实现Observer接口,Observer接口定义如下:

    public interface Observer {
         /**
         *当被观察者发生变化,并调用了notifyObserver方法,就调用该方法
         * @param o   被观察者
         * @param args  修改的内容
         */
        void update(Observable o, Object arg);
    }
    

    例:

    package sl.com.designmodedemo.observer;
    import java.util.Observable;
    import java.util.Observer;
    /**
     * 定义房子为被观察者
     */
    class House extends Observable{
        private float price ;   //定义房子价格
        public House(float price) {
            this.price = price;
        }
        public float getPrice() {
            return price;
        }
        public void setPrice(float price) {
            this.price = price;
            setChanged();           //通知变化点
            notifyObservers(price);      //通知所有观察者价格改变
        }
        @Override
        public String toString() {
            return "房子的价格是:" + this.price;
        }
    }
    /**
     * 房子价格变化观察者
     */
    class HousePriceObserver implements Observer{
        private String name ;       //观察房子价格变化的人名
        public HousePriceObserver(String name) {
            this.name = name;
        }
        @Override
        public void update(Observable o, Object arg) {
                if (arg instanceof Float){              //判断参数类型
                    System.out.println(this.name + " 观察到的价格更改为:" + ((float)arg));
                }
        }
    }
    
    /**
     * 测试
     */
    public class Test {
        public static void main(String args[]){
            House house = new House(1000000.0F);
            HousePriceObserver observer1 = new HousePriceObserver("观察者A");
            HousePriceObserver observer2 = new HousePriceObserver("观察者B");
            HousePriceObserver observer3 = new HousePriceObserver("观察者C");
            //加入观察者
            house.addObserver(observer1);
            house.addObserver(observer2);
            house.addObserver(observer3);
            //输出房子价格
            System.out.println(house);
            //修改房子价格
            house.setPrice(2000000.0F);
            System.out.println(house);
        }
    }
    

    程序运行结果为:

    房子的价格是:1000000.0
    观察者C 观察到的价格更改为:2000000.0
    观察者B 观察到的价格更改为:2000000.0
    观察者A 观察到的价格更改为:2000000.0
    房子的价格是:2000000.0
    

    从程序运行结果可以发现,多个观察者都在观察着价格的变化,当被观察者房子价格一变化,则所有观察者都会知道;、

    三、Android 源码分析

    ListView是Android中重要控件之一,而ListView有一个Adapter,通常我们在给ListView的数据进行操作变化后,都会调用Adapter的notifyDataSetChanged()方法,这是为什么呢?下面我们从源码解析:
    第一步,跟进notifyDataSetChanged()方法,这个方法定义在android.widget的BaseAdapter中,具体代码如下:

    public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
        //数据集观察者
        private final DataSetObservable mDataSetObservable = new DataSetObservable();
        
        //代码省略
    
        public void registerDataSetObserver(DataSetObserver observer) {
            mDataSetObservable.registerObserver(observer);
        }
    
        public void unregisterDataSetObserver(DataSetObserver observer) {
            mDataSetObservable.unregisterObserver(observer);
        }
        //当数据集变化时,通知所有观察者
       public void notifyDataSetChanged() {
            mDataSetObservable.notifyChanged();
        }
    }
    

    从这里应该看出来BaseAdapter就是一个观察者模式,那么BaseAdapter是如何运作的?这些观察者又是什么?下面接着一步一步的分析。
    现在先到mDataSetObservalbe.notifyChanged()的源码看看:

    public class DataSetObservable extends Observable<DataSetObserver> {
        /**
        * 调用每个观察者的onChanged函数来通知他们被观察者发生了变化
        */
       public void notifyChanged() {
            synchronized(mObservers) {
                for (int i = mObservers.size() - 1; i >= 0; i--) {
                    mObservers.get(i).onChanged();
                }
            }
        }
        //代码省略
    }
    

    这个代码很简单,就是在mDataSetObservable.notifyChanged()中遍历所有的观察者,并且调用他的onChanged()方法,从而告知观察者发生了变化。
    那么 这些观察者从哪里来的呢?其实这些观察者是就是ListView在setAdapter方法设置Adapter产生的,我们看相关代码:

        @Override
        public void setAdapter(ListAdapter adapter) {
            //如果已经有了一个Adapter,并且mDataSetObserver不为空
            if (mAdapter != null && mDataSetObserver != null) {
                //先注销该Adapter的观察者
                mAdapter.unregisterDataSetObserver(mDataSetObserver);
            }
    
            //代码省略
           
            super.setAdapter(adapter);
    
            if (mAdapter != null) {
                mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
                mOldItemCount = mItemCount;
                //获取数据的数量
                mItemCount = mAdapter.getCount();
                checkFocus();
               //注意这里:创建了一个数据观察者
                mDataSetObserver = new AdapterDataSetObserver();
                //将这个观察者注册到Adapter中,实际上是注册到DataSetObservable中
                mAdapter.registerDataSetObserver(mDataSetObserver);
                //代码省略 
            } else {
               //代码省略
             }
            requestLayout();
        }
    

    从程序可以看到,在设置Adapter的时会构建一个AdapterDataSetObserver,这就是上面说的观察者,最后将这个观察者注册到了Adapter,这样我们的被观察者、观察者就都有了;
    那么AdapterDataSetObserver是什么?它如何运作?那么现在来看看,AdapterDataObserver定义在ListView的父类AbsListView中,具体代码如下:

     class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
            @Override
            public void onChanged() {
                super.onChanged();
                if (mFastScroll != null) {
                    mFastScroll.onSectionsChanged();
                }
            }
            @Override
            public void onInvalidated() {
                super.onInvalidated();
                if (mFastScroll != null) {
                    mFastScroll.onSectionsChanged();
                }
            }
        }
    

    它又继承自AbsListView的父类AdapterView的AdapterDataSetObserver,具体代码如下:

    class AdapterDataSetObserver extends DataSetObserver {
            private Parcelable mInstanceState = null;
    
        //调用Adapter的notifyDataSetChanged的时会调用所有观察者的onChanged()方法,核心就是这里
          @Override
            public void onChanged() {
                mDataChanged = true;
                mOldItemCount = mItemCount;
                mItemCount = getAdapter().getCount();
    
                // Detect the case where a cursor that was previously invalidated has
                // been repopulated with new data.
                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;
            }
    }
    

    到这里就知道了,当ListView的数据发生变化时,调用Adapter的notifyDataSetChanged(),这个方法又调用了DataSetObservable的notifyChanged()方法,这个方法会调用所有观察者AdapterDataSetObserver的onChanged(),在onChanged函数中又会调用ListView重新布局的函数和使得ListView刷新界面,这就是一个观察者模式;
    现在再整理一下这个过程,AdapterView中又一个内部类AdapterDataSetObserver,在ListView设置Adapter时会构建一个AdapterDataSetObserver,并且注册到Adapter中,这就是一个观察者。而Adapter中有一个数据集被观察者DataSetObservable,在数据数量发生变更时,开发者手动调用Adapter.notifyDataSetChanged(),而notifyDataSetChanged()实际上是调用DataObservable的notifyChanged()方法,该方法会遍历所有的观察者的onChanged()。在AdapterDataSetObserver的onChanged()会获取Adpaer中数据集的新数量,然后调用ListView的requestLayout()方法重新进行布局,更新用户界面。

    相关文章

      网友评论

          本文标题:设计模式之观察者模式

          本文链接:https://www.haomeiwen.com/subject/anpleqtx.html