单丹丹 韩冬
摘要:该文介绍了设计模式中观察者模式的基本概念,在理解观察者模式的基础上,对Android源码中观察者模式的运用进行了深入的分析,说明了观察者模式在程序设计中的重要性。
关键词:设计模式;观察者模式;Android源码
中图分类号:TP311 文献标识码:A文章编号:1009-3044(2017)02-0068-02
1觀察者模式介绍
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
2观察者模式使用场景
1)当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
2)当对一个对象的改变需要同时改变其他对象, 而不知道具体有多少对象需要被改变。
3)当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之, 不希望这些对象是紧密耦合的。
3观察者模式中的角色及UML类图表示
1)抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
2)具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
3)抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
4)具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
用UML类图表示如下:
4 观察者模式的Android源码实现
Adapter是ListView中最重要的一个点。向ListView中添加数据后,都会调用notifyDataSetChanged()方法。notifyDataSetChanged方法定义在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();}}
上段代码中mDataSetObservable.notifyChanged()函数代码如下:
public class DataSetObservable extends Observable
public void notifyChanged() {
synchronized(mObservers) {
// 遍历调用所有观察者的onChanged方式
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();}}}
// 代码省略
}
上段代码中的观察者由ListView通过setAdapter方法来设置Adapter时构建的AdapterDataSetObserver创建,代码如下:
public void setAdapter(ListAdapter adapter) {
// 若已有了一个adapter,则先注销该Adapter对应的观察者
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver); }
// 代码省略
super.setAdapter(adapter);
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
// 获取数据的数量
mItemCount = mAdapter.getCount();
// 创建一个一个数据集观察者
mDataSetObserver = new AdapterDataSetObserver();
// 将这个观察者注册到Adapter中,实际上是注册到DataSetObservable中
mAdapter.registerDataSetObserver(mDataSetObserver);
// 代碼省略
} else {// 代码省略 }
requestLayout();}
通过以上的代码,被观察者、观察者都已经被创建。
下面具体说明AdapterDataSetObserver是如何运作。AdapterDataSetObserver定义在ListView的父类AbsListView中,代码如下 :
class AdapterDataSetObserver extends AdapterView
public void onChanged() {
super.onChanged();
if (mFastScroller != null) {
mFastScroller.onSectionsChanged();}}
//代码省略
}
同时AdapterDataSetObserver又继承自AbsListView的父类AdapterView的AdapterDataSetObserver。当ListView的数据发生变化时,会调用Adapter的notifyDataSetChanged函数,这个函数中会调用DataSetObservable的notifyChanged函数,notifyChanged函数又会调用所有观察者的onChanged方法。这就是一个观察者模式!
最后我们对观察者模式的源码实现进行一个梳理:AdapterView中有一个内部类AdapterDataSetObserver,在ListView设置Adapter时会构建一个AdapterDataSetObserver,并且注册到Adapter中,这就是一个观察者。而Adapter中包含一个可观察者数据集DataSetObservable,在数据数量发生变更时,开发者手动调用AdapternotifyDataSetChanged,而notifyDataSetChanged实际上会调用DataSetObservable的notifyChanged函数,该函数又会遍历所有观察者的onChanged函数。在AdapterDataSetObserver的onChanged函数中会获取Adapter中数据集的新数量,然后调用ListView的requestLayout()方法重新进行布局,从而对用户界面进行更新。
上述代码可以运用于杂志订阅的事例中,杂志是主题,观察者是订阅者,当出版新杂志时候,这个事件会自动通知所有的订阅者。除此以外也可以运用于气象站,为气象站提供用户订阅气象信息的服务。总是,观察者模式在日常生活中的运用十分广泛。
5观察者模式总结
观察者模式的主要的作用就是对对象解耦,将观察者和被观察者完全隔离。
1)观察者模式的优点
观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。
2)观察者模式的缺点
在应用观察者模式时需要考虑一下开发小路问题,程序中包括一个被观察者和多个被观察者额,开发和调试比较复杂,而且Java中的消息的通知默认是顺序执行的,一个观察者的卡顿会影响整体的执行效率。在这种情况下,一般考虑采用异步的方式。
3)观察者模式的重要性
观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,它可以将消息一一通知给所有的观察者。观察者模式基于接口而不是具体的实现的特点,为程序设计提供了更大的灵活性,在程序设计中有着重要的地位。
参考文献:
[1] 何红辉,关爱民.Android源码设计模式解析与实战[M].北京:人民邮电出版社, 2015:224-245.
[2] 何宏辉.Android开发进阶从小工到专家[M].北京:人民邮电出版社, 2016:195-215.
[3] 郭霖.第一行代码[M].北京:人民邮电出版社, 2014:127-135.
[4] 李刚.疯狂安卓讲义[M].北京:电子工业出版社, 2015:88-97.