Observable与Observer源码分析及用法

观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
  观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己

一、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
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
128
129
130
131
132
133
package java.util;
/**
* Observable is used to notify a group of Observer objects when a change
* occurs. On creation, the set of observers is empty. After a change occurred,
* the application can call the {@link #notifyObservers()} method. This will
* cause the invocation of the {@code update()} method of all registered
* Observers. The order of invocation is not specified. This implementation will
* call the Observers in the order they registered. Subclasses are completely
* free in what order they call the update methods.
*
* @see Observer
*/
public class Observable {
List<Observer> observers = new ArrayList<Observer>();
boolean changed = false;
/**
* Constructs a new {@code Observable} object.
*/
public Observable() {
}
/**
* Adds the specified observer to the list of observers. If it is already
* registered, it is not added a second time.
*
* @param observer
* the Observer to add.
*/
public void addObserver(Observer observer) {
if (observer == null) {
throw new NullPointerException("observer == null");
}
synchronized (this) {
if (!observers.contains(observer))
observers.add(observer);
}
}
/**
* Clears the changed flag for this {@code Observable}. After calling
* {@code clearChanged()}, {@code hasChanged()} will return {@code false}.
*/
protected void clearChanged() {
changed = false;
}
/**
* Returns the number of observers registered to this {@code Observable}.
*
* @return the number of observers.
*/
public int countObservers() {
return observers.size();
}
/**
* Removes the specified observer from the list of observers. Passing null
* won't do anything.
*
* @param observer
* the observer to remove.
*/
public synchronized void deleteObserver(Observer observer) {
observers.remove(observer);
}
/**
* Removes all observers from the list of observers.
*/
public synchronized void deleteObservers() {
observers.clear();
}
/**
* Returns the changed flag for this {@code Observable}.
*
* @return {@code true} when the changed flag for this {@code Observable} is
* set, {@code false} otherwise.
*/
public boolean hasChanged() {
return changed;
}
/**
* If {@code hasChanged()} returns {@code true}, calls the {@code update()}
* method for every observer in the list of observers using null as the
* argument. Afterwards, calls {@code clearChanged()}.
* <p>
* Equivalent to calling {@code notifyObservers(null)}.
*/
public void notifyObservers() {
notifyObservers(null);
}
/**
* If {@code hasChanged()} returns {@code true}, calls the {@code update()}
* method for every Observer in the list of observers using the specified
* argument. Afterwards calls {@code clearChanged()}.
*
* @param data
* the argument passed to {@code update()}.
*/
@SuppressWarnings("unchecked")
public void notifyObservers(Object data) {
int size = 0;
Observer[] arrays = null;
synchronized (this) {
if (hasChanged()) {
clearChanged();
size = observers.size();
arrays = new Observer[size];
observers.toArray(arrays);
}
}
if (arrays != null) {
for (Observer observer : arrays) {
observer.update(this, data);
}
}
}
/**
* Sets the changed flag for this {@code Observable}. After calling
* {@code setChanged()}, {@code hasChanged()} will return {@code true}.
*/
protected void setChanged() {
changed = true;
}
}

从源码可以看出,Observable类中有两个方法对Observer特别重要,一个是setChange()方法用来设置一个内部标志位注明数据发生了变化;一个是notifyObservers()方法会去调用一个列表中所有的Observer的update()方法,通知它们数据发生了变化。
Observer通过Observable的addObserver()方法把自己添加到这个列表中。这个列表虽然由Observable拥有,但Observable并不知道到底有哪些Observer正在观察等待通知。Observable只提供一个方法让Observer能把自己添加进列表,并保证会去通知Observer发生了变化。通过这种机制,可以有任意多个Observer对Observable进行观察,而不影响Observable的实现。
Observable的所有方法都是同步的,保证了在一个线程对其标志位、列表进行操作时,不会有其它线程也在操作它。
Observable的notifyObservers(Object obj)形式可以再调用update时将参数传进去。通知顺序通常时越晚加入列表的越先通知。update会被依次调用,由于一个update返回后下一个update才被调用,这样当update中有大量操作时,最好将其中的工作拿到另一个线程或者Observer本身同时也是一个Thread类,Observer先挂起,在update中被唤醒,这样会有一个隐患,Observer线程还没来得及挂起,update就被调用了,通知消息就这样被错过了,一种解决办法是在Observer中实现一个同步的队列结构,并有一个类来封装参数,update实现一个参数类的对象把接收到的通知消息的参数封装在里面,然后把其加进队列,run方法从队列中移除参数对象,并进行处理,这保证了没有通知信息被丢失。

二、Observer接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package java.util;
/**
* {@code Observer} is the interface to be implemented by objects that
* receive notification of updates on an {@code Observable} object.
*
* @see Observable
*/
public interface Observer {
/**
* This method is called if the specified {@code Observable} object's
* {@code notifyObservers} method is called (because the {@code Observable}
* object has been updated.
*
* @param observable
* the {@link Observable} object.
* @param data
* the data passed to {@link Observable#notifyObservers(Object)}.
*/
void update(Observable observable, Object data);
}

从源码可以看出Observer接口只有update()方法,当Observable类调用setChange()方法注明数据发生了变化;同时调用notifyObservers()方法通知列表中所有的Observer调用update()方法,通知它们数据发生了变化,更新数据。

三、简单用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.Observable;
public class SimpleObservable extends Observable
{
private int data = 0;
public int getData(){
return data;
}
public void setData(int i){
if(this.data != i){
this.data = i;
setChange(); //注明数据发生了变化
}
notifyObservers();
//只有在setChange()被调用后,notifyObservers()才会去调用update(),否则什么都不干。
}
}
}
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
import java.util.Observable;
import java.util.Observer;
public class SimpleObserver implements Observer
{
public SimpleObserver(SimpleObservable so){
so.addObserver(this );
}
public void update(Observable o,Object arg/*任意对象,用于传递参数*/){
System.out.println(“Data has changed to” + (SimpleObservable)o.getData());
}
}
public class SimpleTest
{
public static void main(String[] args){
SimpleObservable doc = new SimpleObservable ();
SimpleObserver view = new SimpleObserver (doc);
doc.setData(1);
doc.setData(2);
doc.setData(2);
doc.setData(3);
}
}

打印结果:
Data has changed to 1
Data has changed to 2 //第二次setData(2)时由于没有setChange,所以update没被调用
Data has changed to 3

热评文章