观察者模式

例子及分析

观察者就好比一个可以检测身体信息的手环,该手环每各一段时间会更新一下你的数据,并通过震动(或语音播报)提示你查看数据。

在上面这个例子中,手环就是起到观测者(Observer)的作用,身体是被观测者(Observed),我们将 观测者 注册到(戴到) 被观测者 上, 被观测者的数据发生了变化后主动去告诉 观测者

类图

类图

IObserver是观察者的接口,IObserverd是被观察者的接口。
Observed实现IObserved接口,ConcreteObserver实现IObserver接口。

代码

1
2
3
4
5
6
7
8
9
10
// 观察者接口
public interface IObserver{
// 这里需要传个参数,否则不知道更新了啥
void update(float newVal);
}
// 被观察者接口
public interface IObserved{
void addObserver(IObserver observer);
void removeObserver(IObserver observer);
}
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
// 被观察者实现,这里拿上面的例子举例
public class Body implements IObserved, Runnable{
private float heartRate;
private List<IObserver> observers;
@Override
public void run(){
while(true){
// 不断更新数据
// ......

try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
}
}

/**
* 添加观察者
* @param observer 观察者实例
*/
@Override
public void addObserver(IObserver observer){
this.observers.add(observer);
}

/**
* 移除观察者
* @param observer 观察者实例
*/
@Override
public void removeObserver(IObserver observer){
this.observers.remove(observer);
}

/**
* 通知观察者
*/
@Override
public void notifyObserver(){
// 防止在通知过程中,心率数值发生改变
float heartRate = this.heartRate;
for(IObserver observer: observers){
observer.update(heartRate);
}
}
}
1
2
3
4
5
6
7
8
9
10
// 观察者具体实现
public class Band implements IObserver{
/*
* 当心率数据发生变化时,通知该观察者
*/
@Override
public void update(float newVal){
System.out.println("语音播报:心率发生变化 -----> " + newVal);
}
}
1
2
3
4
5
6
7
8
9
10
public class RealWorld{
public static void main(String[] args){
// 实例化一个人
Body body = new Body();
// 实例化一个智能手环
Band band = new Band();
// 把手环戴手腕上
body.addObserver(band);
}
}

结论

观察者模式在软件架构中,通常是用在数据监听方面,当数据改变后实时进行通知,这里的数据定义比较广泛,有时候是状态——比如Tomcat的Lifecycle组件:当一个容器进入某个状态,会通知所有的组件“我已经进入XXX状态,你们要做什么快做!”;有时候也真的是数据——比如Android上的LoadingProgress,每处理完一部分通知它重新绘制一下。

总的来说,观察者模式的核心在于回调。