设计模式-观察者模式

1.观察者模式的定义及使用场景

观察者模式是一个使用率非常高的模式,它最常用的地方是GUI系统,订阅-发布系统。因为这个模式的一个重要作用就是解耦,将被观察者和观察者解耦,使得它们之间的依赖性更小。

定义:

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所以依赖于它的对象都会得到通知并被自动更新

使用场景:

  • 关联行为场景,需要注意的是,关联行为时可拆分的,而不是“组合”关系;
  • 事件多级触发场景
  • 跨系统的消息交换场景,如消息队列、事件总线的处理机制

这里写图片描述

2. 观察者模式的优缺点

2.1优点

  • 观察者和被观察者之间是抽象解耦,应对业务变化
  • 增强系统灵活性、可扩展性

    2.2缺点

    在应用观察者模式时需要考虑一下开发效率和运行效率问题,程序中包括一个被观察者、多个观察者、开发和调试等内容会比较复杂,而且在Java中消息的通知默认是顺序执行,一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般考虑采用异步的方式

    3. 观察者模式的实现方式

    1
    2
    3
    4
    public interface Observer {
    //更新方法
    public void update();
    }
1
2
3
4
5
6
public class ConcreteObsever implements Observer {
@Override
public void update() {
System.out.println("接收到信息,并进行处理!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public abstract class Subject {
//定义一个观察者数组
private List<Observer> observers = new ArrayList<>();

//增加一个观察者
public void addObserver(Observer o) {
this.observers.add(o);
}

//删除一个观察者
public void removeObserver(Observer o) {
this.observers.remove(o);
}

//通知所有观察者
public void notifyObservers() {
for (Observer o : this.observers) {
o.update();
}
}
}
1
2
3
4
5
6
7
public class ConcreteSubject extends Subject {

//具体的业务
public void doSomeThing() {
super.notifyObservers();
}
}
1
2
3
4
5
6
7
8
9
10
public class Test {

public static void main(String args[]) {
//创建一个被观察者
ConcreteSubject subject=new ConcreteSubject();
Observer obs=new ConcreteObsever();
subject.addObserver(obs);
subject.doSomeThing();
}
}

4. 观察者模式在Android中的实际应用

RecycleView是Android中最重要的控件之一,而RecycleView最重要的一个功能就是Adapter。通过我们往RecycleView添加数据后,都会调用Adapter的notifyDataSetChanged()方法,这是为什么?
首先我们看下Adapter的实现,他是RecycleView的一个内部类。

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
public static abstract class Adapter<VH extends ViewHolder> {
private final AdapterDataObservable mObservable = new AdapterDataObservable();
private boolean mHasStableIds = false;

public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);

public abstract void onBindViewHolder(VH holder, int position);

public void onBindViewHolder(VH holder, int position, List<Object> payloads) {
onBindViewHolder(holder, position);
}

public final VH createViewHolder(ViewGroup parent, int viewType) {
TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG);
final VH holder = onCreateViewHolder(parent, viewType);
holder.mItemViewType = viewType;
TraceCompat.endSection();
return holder;
}

public final void bindViewHolder(VH holder, int position) {
holder.mPosition = position;
if (hasStableIds()) {
holder.mItemId = getItemId(position);
}
holder.setFlags(ViewHolder.FLAG_BOUND,
ViewHolder.FLAG_BOUND | ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID
| ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);
TraceCompat.beginSection(TRACE_BIND_VIEW_TAG);
onBindViewHolder(holder, position, holder.getUnmodifiedPayloads());
holder.clearPayload();
TraceCompat.endSection();
}

public int getItemViewType(int position) {
return 0;
}

public void setHasStableIds(boolean hasStableIds) {
if (hasObservers()) {
throw new IllegalStateException("Cannot change whether this adapter has " +
"stable IDs while the adapter has registered observers.");
}
mHasStableIds = hasStableIds;
}

public long getItemId(int position) {
return NO_ID;
}

public abstract int getItemCount();

public final boolean hasStableIds() {
return mHasStableIds;
}

public void onViewRecycled(VH holder) {
}

public boolean onFailedToRecycleView(VH holder) {
return false;
}

public void onViewAttachedToWindow(VH holder) {
}

public void onViewDetachedFromWindow(VH holder) {
}

public final boolean hasObservers() {
return mObservable.hasObservers();
}

public void registerAdapterDataObserver(AdapterDataObserver observer) {
mObservable.registerObserver(observer);
}

public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
mObservable.unregisterObserver(observer);
}

public void onAttachedToRecyclerView(RecyclerView recyclerView) {
}

public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
}

public final void notifyDataSetChanged() {
mObservable.notifyChanged();
}

public final void notifyItemChanged(int position) {
mObservable.notifyItemRangeChanged(position, 1);
}

public final void notifyItemChanged(int position, Object payload) {
mObservable.notifyItemRangeChanged(position, 1, payload);
}

public final void notifyItemRangeChanged(int positionStart, int itemCount) {
mObservable.notifyItemRangeChanged(positionStart, itemCount);
}

public final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
mObservable.notifyItemRangeChanged(positionStart, itemCount, payload);
}

public final void notifyItemInserted(int position) {
mObservable.notifyItemRangeInserted(position, 1);
}

public final void notifyItemMoved(int fromPosition, int toPosition) {
mObservable.notifyItemMoved(fromPosition, toPosition);
}

public final void notifyItemRangeInserted(int positionStart, int itemCount) {
mObservable.notifyItemRangeInserted(positionStart, itemCount);
}

public final void notifyItemRemoved(int position) {
mObservable.notifyItemRangeRemoved(position, 1);
}

public final void notifyItemRangeRemoved(int positionStart, int itemCount) {
mObservable.notifyItemRangeRemoved(positionStart, itemCount);
}
}

我们可以看到notifyDataSetChange()中调用了mObservable.notifyChange()。继续看AdapterDataObservable类

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
33
34
35
36
37
38
39
40
41
42
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();
}
}

public void notifyItemRangeChanged(int positionStart, int itemCount) {
notifyItemRangeChanged(positionStart, itemCount, null);
}

public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {

for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload);
}
}

public void notifyItemRangeInserted(int positionStart, int itemCount) {

for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeInserted(positionStart, itemCount);
}
}

public void notifyItemRangeRemoved(int positionStart, int itemCount) {

for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeRemoved(positionStart, itemCount);
}
}

public void notifyItemMoved(int fromPosition, int toPosition) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeMoved(fromPosition, toPosition, 1);
}
}
}

Observable是一个被观察者:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public abstract class Observable<T> {
/**
* The list of observers. An observer can be in the list at most
* once and will never be null.
*/
protected final ArrayList<T> mObservers = new ArrayList<T>();

/**
* Adds an observer to the list. The observer cannot be null and it must not already
* be registered.
* @param observer the observer to register
* @throws IllegalArgumentException the observer is null
* @throws IllegalStateException the observer is already registered
*/
public void registerObserver(T observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
if (mObservers.contains(observer)) {
throw new IllegalStateException("Observer " + observer + " is already registered.");
}
mObservers.add(observer);
}
}

/**
* Removes a previously registered observer. The observer must not be null and it
* must already have been registered.
* @param observer the observer to unregister
* @throws IllegalArgumentException the observer is null
* @throws IllegalStateException the observer is not yet registered
*/
public void unregisterObserver(T observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
int index = mObservers.indexOf(observer);
if (index == -1) {
throw new IllegalStateException("Observer " + observer + " was not registered.");
}
mObservers.remove(index);
}
}

/**
* Remove all registered observers.
*/
public void unregisterAll() {
synchronized(mObservers) {
mObservers.clear();
}
}
}

AdapterDataObserver 的派生类RecyclerViewDataObserver: mObserver是RecycleView的一个变量

1
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
private class RecyclerViewDataObserver extends AdapterDataObserver {
@Override
public void onChanged() {
assertNotInLayoutOrScroll(null);
if (mAdapter.hasStableIds()) {
// TODO Determine what actually changed.
// This is more important to implement now since this callback will disable all
// animations because we cannot rely on positions.
mState.mStructureChanged = true;
setDataSetChangedAfterLayout();
} else {
mState.mStructureChanged = true;
setDataSetChangedAfterLayout();
}
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}

@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
triggerUpdateProcessor();
}
}

@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeInserted(positionStart, itemCount)) {
triggerUpdateProcessor();
}
}

@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeRemoved(positionStart, itemCount)) {
triggerUpdateProcessor();
}
}

@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeMoved(fromPosition, toPosition, itemCount)) {
triggerUpdateProcessor();
}
}

void triggerUpdateProcessor() {
if (mPostUpdatesOnAnimation && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
}

RecycleView的setAdapter方法,可以看到里面调用了unregisterAdapterDataObserver及registerAdapterDataObserver方法进行取消注册及注册。

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
33
34
35
36
37
38
39
40
41
42
43
public void setAdapter(Adapter adapter) {
// bail out if layout is frozen
setLayoutFrozen(false);
setAdapterInternal(adapter, false, true);
requestLayout();
}

private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
boolean removeAndRecycleViews) {
if (mAdapter != null) {
mAdapter.unregisterAdapterDataObserver(mObserver);
mAdapter.onDetachedFromRecyclerView(this);
}
if (!compatibleWithPrevious || removeAndRecycleViews) {
// end all running animations
if (mItemAnimator != null) {
mItemAnimator.endAnimations();
}
// Since animations are ended, mLayout.children should be equal to
// recyclerView.children. This may not be true if item animator's end does not work as
// expected. (e.g. not release children instantly). It is safer to use mLayout's child
// count.
if (mLayout != null) {
mLayout.removeAndRecycleAllViews(mRecycler);
mLayout.removeAndRecycleScrapInt(mRecycler);
}
// we should clear it here before adapters are swapped to ensure correct callbacks.
mRecycler.clear();
}
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;
markKnownViewsInvalid();
}

到这里我们知道,setAdapter()方法会进行观察者的注册,当RecycleView的数据发送变化的时,调用了Adapter的notifyDataSetChange(),这个函数又会调用 AdapterDataObservable的notifyChanged();该函数会遍历所有的观察者的onChange函数,在 RecyclerViewDataObserver的onChange()函数中会获取Adapter中数据集的新数量,然后调用RecycleView的requestLayout()方法重新进行布局,更新用户的界面。这就是一个观察者模式!