Java基础笔记 - JDK中提供的观察者模式支持

JDK中也提供了对观察者模式的内置支持。

1、JDK中观察者模式的实现原理:

Observable类用于创建可以观测到你的程序中其他部分的子类。当这种子类的对象发生变化时,观测类被通知。观测类必须实现定义了update()方法的Observer接口。当一个观测程序被通知到一个被观察对象的改变时,update()方法被调用。

2、Observable类:

1
public class Observable extends Object

此类表示模型视图范例中的 observable 对象,或者说“数据”。可将其子类化,表示应用程序想要观察的对象。

一个 observable 对象可以有一个或多个观察者。观察者可以是实现了 Observer 接口的任意对象。一个 observable 实例改变后,调用 Observable 的 notifyObservers 方法的应用程序会通过调用观察者的 update 方法来通知观察者该实例发生了改变。

2.1、相关方法:

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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;

/** Construct an Observable with zero Observers. */

public Observable() {
obs = new Vector<>();
}

/**
* Adds an observer to the set of observers for this object, provided
* that it is not the same as some observer already in the set.
* The order in which notifications will be delivered to multiple
* observers is not specified. See the class comment.
*
* @param o an observer to be added.
* @throws NullPointerException if the parameter o is null.
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}

/**
* Deletes an observer from the set of observers of this object.
* Passing <CODE>null</CODE> to this method will have no effect.
* @param o the observer to be deleted.
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}

/**
* If this object has changed, as indicated by the
* <code>hasChanged</code> method, then notify all of its observers
* and then call the <code>clearChanged</code> method to
* indicate that this object has no longer changed.
* <p>
* Each observer has its <code>update</code> method called with two
* arguments: this observable object and <code>null</code>. In other
* words, this method is equivalent to:
* <blockquote><tt>
* notifyObservers(null)</tt></blockquote>
*
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers() {
notifyObservers(null);
}

/**
* If this object has changed, as indicated by the
* <code>hasChanged</code> method, then notify all of its observers
* and then call the <code>clearChanged</code> method to indicate
* that this object has no longer changed.
* <p>
* Each observer has its <code>update</code> method called with two
* arguments: this observable object and the <code>arg</code> argument.
*
* @param arg any object.
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;

synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}

for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}

/**
* Clears the observer list so that this object no longer has any observers.
*/
public synchronized void deleteObservers() {
obs.removeAllElements();
}

/**
* Marks this <tt>Observable</tt> object as having been changed; the
* <tt>hasChanged</tt> method will now return <tt>true</tt>.
*/
protected synchronized void setChanged() {
changed = true;
}

/**
* Indicates that this object has no longer changed, or that it has
* already notified all of its observers of its most recent change,
* so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.
* This method is called automatically by the
* <code>notifyObservers</code> methods.
*
* @see java.util.Observable#notifyObservers()
* @see java.util.Observable#notifyObservers(java.lang.Object)
*/
protected synchronized void clearChanged() {
changed = false;
}

/**
* Tests if this object has changed.
*
* @return <code>true</code> if and only if the <code>setChanged</code>
* method has been called more recently than the
* <code>clearChanged</code> method on this object;
* <code>false</code> otherwise.
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#setChanged()
*/
public synchronized boolean hasChanged() {
return changed;
}

/**
* Returns the number of observers of this <tt>Observable</tt> object.
*
* @return the number of observers of this object.
*/
public synchronized int countObservers() {
return obs.size();
}
}

3、Observer接口:

1
public interface Observer

一个可在观察者要得到 observable 对象更改通知时可实现 Observer 接口的类。

3.1、相关方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}

4、被观察对象的工作原理按照如下规则:

如果它被改变了,它必须调用setChanged()方法。

当它准备通知观测程序它的改变时,它必须调用notifyObservers()方法。该方法导致了在观测对象中对update()方法的调用。

注意:当对象在调用notifyObservers()方法之前没有调用setChanged()方法,就不会有动作发生。也就是说在update()方法被调用之前,被观测对象必须调用setChanged()notifyObservers()两个方法。

5、下面写一个例子实现从被观察对象向观察者发送执行动作:

image-20191110222926426

其中,update方法,第一个参数为被观察者,也叫事件源;第二个参数,也就是sendMessage方法参数,为事件对象。

被观察者:

1
2
3
4
5
6
7
8
9
10
11
/**
* 被观察者
*/
public class Monitored extends Observable {

public void sendMessage(String str){
// 需要先调用setChanged方法
this.setChanged();
this.notifyObservers(str);
}
}

观察者1:

1
2
3
4
5
6
7
8
9
10
/**
* 观察者1
*/
public class Watcher1 implements Observer {

@Override
public void update(Observable o, Object arg) {
System.out.println("Watcher1 receive:" + arg);
}
}

观察者2:

1
2
3
4
5
6
7
8
9
10
/**
* 观察者2
*/
public class Watcher2 implements Observer {

@Override
public void update(Observable o, Object arg) {
System.out.println("Watcher2 receive:" + arg);
}
}

在客户端使用观察者角色:

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
//创建被观察对象
Monitored monitored = new Monitored();
//创建两个观察者
Watcher1 watcher1 = new Watcher1();
Watcher2 watcher2 = new Watcher2();
//添加观察者
monitored.addObserver(watcher1);
monitored.addObserver(watcher2);
//被观察者发送消息给观察者
monitored.sendMessage("这是一条消息");
}
arthinking wechat
欢迎关注itzhai公众号,欢迎关注itzhai公众号,获取更多最新的文章