XDRush

设计模式跟风作之观察者模式

1 观察者模式简介

观察者模式定义了一种一对多的依赖关系,让多个Observer对象同时监听某个Observable(被观察者)对象。当Observable对象在状态发生变化时,会通知所有(或者部分)Observers,让这些observers能够自动更新自己。

2 观察者模式的组成

2.1 抽象Observable角色

把所有对观察者对象的引用保存在一个集合中,每个抽象Observable角色都可以有任意数量的Observer。抽象Observable提供一个接口,可以增加、删除Observer。一般用一个抽象类和接口来实现。

2.2 抽象Observer角色

为所有具体的Observer定义一个接口,在得到Observable的通知时更新自己。

2.3 具体Observable角色

在具体Observable内部状态改变时,给所有注册过的Observers发出通知。具体Observable通常是抽象Observable的一个子类实现。

2.4 具体Observer角色

该角色实现抽象Observer所要求的接口,以便使自己的状态与Observable的状态相协调。通常用一个子类来实现。如果需要,具体Observer角色可以保存一个指向具体Observable角色的引用。

3 观察者模式实现

3.1 抽象Observer实现

1
2
3
4
5
6
/**
* 抽象Observer角色
*/
public interface Watcher {
void update(String str);
}

3.2 抽象Observable实现

1
2
3
4
5
6
7
8
9
10
11
/**
* 抽象Observable角色.
*/
public interface Watched {
void addWatcher(Watcher watcher);
void removeWatcher(Watcher watcher);
void notifyWatchers(String str);
}

3.3 具体Observer实现

1
2
3
4
5
6
7
8
9
10
/**
* 具体的Observer实现
*/
public class ConcreteWatcher implements Watcher {
@Override
public void update(String str) {
System.out.println(str);
}
}

3.4 具体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
/**
* 具体Observable实现
*/
public class ConcreteWatched implements Watched {
private List<Watcher> mWatcherList = new ArrayList<>();
@Override
public void addWatcher(Watcher watcher) {
if (null == watcher) {
return;
}
mWatcherList.add(watcher);
}
@Override
public void removeWatcher(Watcher watcher) {
if (null == watcher) {
return;
}
if (0 == mWatcherList.size()) {
return;
}
mWatcherList.remove(watcher);
}
@Override
public void notifyWatchers(String str) {
for (Watcher watcher : mWatcherList) {
watcher.update(str);
}
}
}

3.5 测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ObservableTest {
public static void main(String[] args) {
Watched employees = new ConcreteWatched();
Watcher employee1 = new ConcreteWatcher();
Watcher employee2 = new ConcreteWatcher();
Watcher employee3 = new ConcreteWatcher();
employees.addWatcher(employee1);
employees.addWatcher(employee2);
employees.addWatcher(employee3);
employees.notifyWatchers("xdrush");
}
}

4 Java中的观察者模式

4.1 Java中的Observer和Observable

Java在java.util.*;包中提供了现成的观察者模式实现,具体的两个类分别是Observer和Observable;这两个类充当上节中的抽象Observer和抽象Observable功能。

4.2 使用示例

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
// 首先定义SimpleObserver
public class SimpleObserver implements Observer {
public SimpleObserver(SimpleObservable observable) {
observable.addObserver(this);
}
@Override
public void update(Observable observable, Object object) {
if (observable instanceof SimpleObservable) {
SimpleObservable simpleObservable = (SimpleObservable) observable;
System.out.println("data has changed to -> " + simpleObservable.getData());
}
}
}
// 定义SimpleObservable
public class SimpleObservable extends Observable {
private int mData = 0;
public void setData(int data) {
if (this.mData == data) {
return;
}
this.mData = data;
setChanged();
notifyObservers();
}
public int getData() {
return mData;
}
}
// 简单测试
public class ObservableTest {
public static void main(String[] args) {
SimpleObservable observable = new SimpleObservable();
SimpleObserver observer1 = new SimpleObserver(observable);
SimpleObserver observer2 = new SimpleObserver(observable);
SimpleObserver observer3 = new SimpleObserver(observable);
observable.setData(5);
observable.setData(6);
observable.setData(6);
}
}

4.3 Observer

Observer接口只提供了一个方法update():

1
2
3
public interface Observer {
void update(Observable observable, Object object);
}

4.4 Observable

Observable提供了几个关键的接口:
(1) setChanged()
用来设置一个内部标志位注明数据发生了变化;只有setChanged()方法被调用,notifyObservers()方法才会被正确的执行;这在notifyObservers()方法源码中有具体的体现;

(2) notifyObservers()/notifyObservers(Object object)
通知所有的Observers数据发生了变化,这时所有的Observer会自动调用复写好的update(Observable, Object)方法来做一些处理。其中Object参数可以用来作为ID,然后在所有的Observer中作判断,每个Observer判断只有接收到的参数ID属于自己的才做一些处理。

其他的方法可直接看源码,比较简单,易于理解。

4.5 使用注意事项

在Observer对象被销毁前一定要用deleteObserver将其从列表中删除,否则因为在Observable中还存在对象的引用,导致Observer不会被垃圾收集,曹成内存泄漏。