设计模式之观察者模式

一、什么叫观察者?

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

  • 观察者模式的定义:定义对象间一种一对多的依赖关系,使得每当一个对象发生改变,则所有依赖她的对象都会等到通知并被自动更新。
  • 使用场景: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 {
    /**
    * 调用每个观察者的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.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()方法重新进行布局,更新用户界面。

你可能感兴趣的:(设计模式之观察者模式)