定义
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所以依赖于它的对象都会得到通知并被自动更新
使用场景
- 关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。
- 时间多级触发场景
- 跨系统的消息交换场景,如消息队列、时间总线的处理机制。
UML 类图
classDiagram
Subject o.. Observer
Subject <|-- ConcreteSubject
Observer <|-- ConcreteObserver
class Subject{
<<abstract>>
+register(Observer)
+unregister(Observer)
+nofityObservers(Object)
}
class ConcreteSubject{
+nofityObservers(Object)
}
class Observer{
<<interface>>
+update(Object)
}
class ConcreteObserver{
+update(Object)
}
- Subject: 抽象主题,也就是被观察者(Observable)角色,抽象主题把所以观察者对象的引用保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以新增和删除观察者对象。
- ConcerteSubject: 具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内容状态发生改变时,给所有注册过的观察者发出通知,具体主题角色又叫做具体观察者(ConsreteObservable)角色。
- Observer: 抽象观察者,改角色是观察者的抽象类,它定义了一个更新接口,使得在得到主题的更改通知时更新自己。
- ConcreteObserver: 具体观察者,该角色实现抽象观察者所定义的更新接口,以便在主题状态发生改变时更新自身的状态。
Android 中的观察者模式
Android源码中有很多使用了观察者模式,比如OnClickListener、ContentObserver、 android.database.Observer 等。还有很多组件库Rxjava、RxAndroid、EventBus;这里我们来看下常用的Adapter的notifyDataSetChanged()。
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 里有一个DataSetObservable 的被观察者,通过register*()、unregister*()方法添加和删除观察者。我们往下看DataSetObservable 这个类
public class DataSetObservable extends Observable<DataSetObserver> {
/**
* 当数据变化时调用每个观察者的onChanged() 方法通知它们
*/
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();
}
}
}
}
这里其实很简单,就是遍历所有观察者并调用它们的onChanged()。接下来我们看是谁调用了BaseAdapter 的 registerDataSetObserver(DataSetObserver observer)方法。
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
//省略代码...
// 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();
//将这个观察者注册到 Adapter 的 DataSetObservable 中
mAdapter.registerDataSetObserver(mDataSetObserver);
//省略代码...
} else {
//省略代码...
}
requestLayout();
}
以上可以看出ListVeiw 中有一个观察者(AdapterDataSetObserver)在setAdapter() 的时候注册到了Adapter 的DataSetObservable 中,当Adapter 调用 notifyDataSetChanged() 方法时就会通知 ListView 中的观察者(AdapterDataSetObserver)更新状态。
小结
观察者模式主要的作用就是解耦,将观察者与被观察者完全隔离,只依赖于 Observer 和 Observable 抽象,提供代码的灵活性和可扩展性。
优点: 观察者和被观察者直接是抽象耦合,应对业务变化。增强系统灵活性、可扩展性。
缺点: 在应用观察者模式时需要考虑一下开发效率和运行效率问题,因为一个被观察者可能直接或间接有很多观察者,Java 消息中的通知默认顺序执行,通知到所以观察者可能需要花费些时间,如果一个观察者卡顿,会影响整体的执行效率,这里一般考虑采用异步的方式。