0%

设计模式之观察者模式

我们在生活中会遇到这样一些例子,比如你订阅了某人的博客,那么这个人发布博客的时候会将消息推送给你,而且不是只推送你自己一人,只要订阅了该人的博客,那么订阅者都会收到通知,像这样的例子生活中实在是太多了。其实这种操作可以抽象一下,A对象(观察者)对B对象(被观察者)的某种变化高度敏感,需要在B变化的一瞬间做出反应,同时在B对象中维护着所有A的集合。我们在实际编程中称这种模式为观察者模式,有时也称为发布/订阅(Publish/Subscribe)模型。

在JDK的util包中已经帮我们实现了观察者模式,不过我们还是先通过自己写代码来看看观察者到底是怎么回事,自己该如何简单的实现,相信通过自己的简单实现,来理解JDK的观察者模式的实现是十分容易的。

在观察者模式中,首先要有两个角色,观察者与被观察者,这两者拥有的功能是不同的。对于观察者,需要有一个方法来接收被观察者发出的信息(update),而对于被观察者而言,需要在其内部维护一个观察者的列表,用来记录需要通知的观察者(list),所以需要一个添加观察者的方法(addWatcher),同时还要有一个方法可以用来移除观察者(removeWatcher), 最后我们需要一个用来通知所有观察者的方法(notifyWatchers), 一切准备就绪,那么我们来看代码吧。

先定义两个接口,观察者(Watcher)和被观察者(Watched),代码如下:

首先是观察者接口,定义了update方法用来接收通知

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 观察者
* @author mingshan
*
*/
public interface Watcher {

/**
* 用来接收通知
*/
void 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
/**
* 被观察者
* @author mingshan
*
*/
public interface Watched {

/**
* 添加观察者
* @param watcher
*/
void addWatcher(Watcher watcher);

/**
* 移除观察者
* @param watcher
*/
void removeWatcher(Watcher watcher);

/**
* 通知观察者
*/
void notifyWatchers();
}

我们先实现被观察者,重写接口的方法,在其内部维护一个列表,用来存放所有的观察者,当需要通知观察者时,我们就可以调用notifyWatchers方法了,遍历通知所有观察者。

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.ArrayList;
import java.util.List;

public class Thief implements Watched {

private List<Watcher> list = new ArrayList<Watcher>();

@Override
public void addWatcher(Watcher watcher) {
list.add(watcher);
}

@Override
public void removeWatcher(Watcher watcher) {
list.remove(watcher);
}

@Override
public void notifyWatchers() {
for (Watcher watcher: list) {
watcher.update();
}
}

}

我们再实现观察者,重写update方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Police implements Watcher {

@Override
public void update() {
System.out.println("小偷正在偷东西,警察行动!");
}

}

------------------------------

public class Inspector implements Watcher {

@Override
public void update() {
System.out.println("小偷正在偷东西,城管行动!");
}

}

最后我们写个测试类测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.junit.Test;

public class ObserverTest {

@Test
public void test() {
Thief thief = new Thief();
Police police = new Police();
Inspector inspector = new Inspector();
thief.addWatcher(police);
thief.addWatcher(inspector);

thief.notifyWatchers();
}
}

以上是我们自己实现的观察者模式,前面说过了在JDK中已经帮我们实现好了观察者模式,那么我们来用一下:

观察者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 被观察者 (JDK)
* @author mingshan
*
*/
public class Thief extends Observable {

@Override
public String toString() {
return "我是小偷-_-";
}

public void work() {
System.out.println("ss准备下手偷东西了!");
setChanged();
notifyObservers("-小偷说话:哈哈,你猜我是谁-");
}
}

观察者:

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 Police implements Observer {

@Override
public void update(Observable o, Object arg) {
System.out.println(o + "小偷正在偷东西,警察行动!"+ arg);
}

}

——————————————————————————————————————

import java.util.Observable;
import java.util.Observer;

public class Inspector implements Observer {

@Override
public void update(Observable o, Object arg) {
System.out.println(o + "小偷正在偷东西,城管行动!" + arg);
}

}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.junit.Test;

public class ObserverTest {

@Test
public void test() {
Thief thief = new Thief();
Police police = new Police();
Inspector inspector = new Inspector();
thief.addObserver(police);
thief.addObserver(inspector);
thief.work();
}
}

在Observable类源码中,我们可以看到有个changed的布尔值成员变量,用来标志当前对象是否已经被改变,所有在通知观察者之前我们将其置为true

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
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;

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

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

/**
* 添加观察者,并且一个观察者只能被添加一次
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}

/**
* 移除观察者
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}

/**
* 通知所有的观察者
*/
public void notifyObservers() {
notifyObservers(null);
}

/**
* 通知所有的观察者(遍历),同时可以将一些信息传递给观察者,实际上是调用观察** 者的update方法
*/
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;

synchronized (this) {

if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}

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

/**
* 删除观察者
*/
public synchronized void deleteObservers() {
obs.removeAllElements();
}

/**
* 将判断当前对象是否改变的flag设置为true
*/
protected synchronized void setChanged() {
changed = true;
}

/**
* 将判断当前对象是否改变的flag设置为false
*/
protected synchronized void clearChanged() {
changed = false;
}

/**
* 判断当前对象是否改变
*
*/
public synchronized boolean hasChanged() {
return changed;
}

/**
* 统计观察者数量
*/
public synchronized int countObservers() {
return obs.size();
}
}

向本文提出修改或勘误建议