定义 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
使用场景
关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合关系”
事件多级触发场景
跨系统的消息交换场景,如消息队列、事件总线的处理机制
UML类图
Subject:抽象对象,也是被观察(Observable)的角色,抽象主题角色把所有观察者对象的引用保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
ConcreteSubject:具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有注册过的观察者发出通知,具体主题角色有叫做具体被观察者(ConcreteObservable)角色。
Observer:抽象观察者,该角色是观察者的抽象类,它定义了一个更新接口,使得在得到猪头的更改通知时更新自己。
ConcreteObserver:具体的观察者,该角色实现抽象观察者角色所定义的更新接口,以便在主题的状态发生改变时更新自己的状态。
Android源码 Android中使用观察者模式的地方很多,在这里以我们常用的RecyclerView为例。当我们往RecyclerView中添加数据后,都会调用Adapter的notifyDataSetChanged方法,其中就使用观察者模式的方式,接下来研究它的实现源码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public abstract static class Adapter <VH extends ViewHolder > { private final AdapterDataObservable mObservable = new AdapterDataObservable(); private boolean mHasStableIds = false ; public void registerAdapterDataObserver (@NonNull AdapterDataObserver observer) { mObservable.registerObserver(observer); } public void unregisterAdapterDataObserver (@NonNull AdapterDataObserver observer) { mObservable.unregisterObserver(observer); } public final void notifyDataSetChanged () { mObservable.notifyChanged(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static class AdapterDataObservable extends Observable <AdapterDataObserver > { public boolean hasObservers () { return !mObservers.isEmpty(); } public void notifyChanged () { for (int i = mObservers.size() - 1 ; i >= 0 ; i--) { mObservers.get(i).onChanged(); } } }
那么这些观察者从哪里来的?这些观察者是在RecyclerView通过setAdapter方法设置的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public void setAdapter (@Nullable Adapter adapter) { setLayoutFrozen(false ); setAdapterInternal(adapter, false , true ); processDataSetCompletelyChanged(false ); requestLayout(); } private void setAdapterInternal (@Nullable Adapter adapter, boolean compatibleWithPrevious, boolean removeAndRecycleViews) { if (mAdapter != null ) { mAdapter.unregisterAdapterDataObserver(mObserver); mAdapter.onDetachedFromRecyclerView(this ); } if (!compatibleWithPrevious || removeAndRecycleViews) { removeAndRecycleViews(); } mAdapterHelper.reset(); final Adapter oldAdapter = mAdapter; mAdapter = adapter; if (adapter != null ) { adapter.registerAdapterDataObserver(mObserver); adapter.onAttachedToRecyclerView(this ); } if (mLayout != null ) { mLayout.onAdapterChanged(oldAdapter, mAdapter); } mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious); mState.mStructureChanged = true ; }
这样注册也就完成了,只要我们调用notifyDataSetChanged,就会调用AdapterDataObservable的notifyChanged方法,这个函数会调用所有观察者(AdapterDataObserver)的onChanged方法。
onChanged实际调用的RecyclerViewDataObserver中的onChanged方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private class RecyclerViewDataObserver extends AdapterDataObserver { RecyclerViewDataObserver() { } @Override public void onChanged () { assertNotInLayoutOrScroll(null ); mState.mStructureChanged = true ; processDataSetCompletelyChanged(true ); if (!mAdapterHelper.hasPendingUpdates()) { requestLayout(); } } }
在onChanged方法中调用requestLayout方法重新布局,更新用户界面。
总结 优点
观察者和被观察者之间是抽象耦合,应对业务变化;
增强系统灵活性、可扩展性。
缺点 在应用观察者模式时需要考虑开发效率和运行效率,程序包括一个被观察者、多个观察者,开发和调试会比较复杂,而且在Java中消息的通知默认是顺序执行,一个观察者卡顿,会影响整体执行效率,在这种情况下,一般采用异步的方式。