观察者模式(又被称为发布-订阅模式、模型-视图模式、源-收听者模式或从属者模式)
观察者模式中,一个目标对象管理所有依赖于它的观察者对象,并且在它本身的状态改变时主动发出通知。
应用场景
拍卖会可以认为是观察者模式的一种,每个投标人都可以出价。拍卖师开始拍卖时,他观察是否有牌子举起出价。每次接受一个新的出价都改变了拍卖的当前价格,并且广播给所有的投标人。
在JDK中的应用
- java.util.EventListener
- javax.servlet.http.HttpSessionBindingListener
- javax.servlet.http.HttpSessionAttributeListener
- javax.faces.event.PhaseListener
参与角色
抽象主题(Subject):
抽象主题提供一个接口,可以增加和删除观察者对象;
Subject把所有观察者对象的引用保存到一个集合里,每个主题都可以有任何数量的观察者;
具体主题(ConcreteSubject):
存储有关状态,这些状态应与目标的状态保持一致;
将有关状态存入具体观察者对象;
在具体主题内部状态改变时,给所有登记过的观察者发出通知;
实现Observer的更新接口以使自身状态与目标的状态保持一致。
抽象观察者(Observer):
为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
具体观察者(ConcreteObserver):
实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
观察者模式的类图
观察者模式的意图是定义对象之间一对多的依赖关系,一个对象状态改变,其他相关联的对象就会得到通知并被自动更新。
观察者模式实例
在这个实例中,观察者能够注册此主题,任何在此主题上的内容提交导致的变化都会通知所有在注册的观察者。
Subject抽象主题:
1
2
3
4
5
6
7
8
9
10
11
12
|
public
interface
Subject {
//注册观察者
public
void
attach(Observer obs);
//移除观察者
public
void
detach(Observer obs);
//通知观察者
public
void
noticeObservers();
//获得主题的更新信息
public
String getUpdate();
}
|
Observer抽象订阅者:
1
2
3
4
5
6
7
8
9
10
|
public
interface
Observer {
/**
* 获取主题变化,由Observer触发
*/
public
void
update();
/**设置主题对象*/
public
void
setSubject(Subject sbj);
}
|
ConcreteSubject具体主题:
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
|
public
class
ConcreteSubject
implements
Subject{
private
String message;
//传递的消息体
private
boolean
changed;
//消息状态标识
//存储注册的观察者集合
private
List<Observer> observers;
public
ConcreteSubject(){
this
.observers=
new
ArrayList<Observer>();
}
/**
* 这里的Subject可以是主题订阅,具体关系中的老师-学生等
*/
@Override
public
void
attach(Observer obs) {
if
(obs==
null
)
throw
new
NullPointerException(
"Null Observer"
);
if
(!observers.contains(obs))
observers.add(obs);
}
@Override
public
void
detach(Observer obs) {
observers.remove(obs);
}
@Override
public
void
noticeObservers() {
List<Observer> temp=
null
;
/**
* 防止观察者收到订阅以前由被观察者发出的消息
*/
synchronized
(ConcreteSubject.
class
) {
if
(!changed)
return
;
temp=
new
ArrayList<>(
this
.observers);
this
.changed=
false
;
}
for
(Observer obs:temp){
/**调用观察者的方法*/
obs.update();
}
}
@Override
public
String getUpdate() {
return
this
.message;
}
public
void
postMessage(String msg){
this
.message=msg;
this
.changed=
true
;
//通知到观察者
noticeObservers();
}
}
|
ConcreteObserver具体观察者:
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
|
public
class
ConcreteObserver
implements
Observer{
//此处用于标注不同的观察者
private
String name;
//消息结果字段
private
String result;
//设置主题
private
Subject subject;
public
ConcreteObserver(String name){
this
.name=name;
}
@Override
public
void
update() {
/**从主题那里取得消息更新*/
result=subject.getUpdate();
/**处理消息*/
System.out.println(name+
" get message "
+result);
}
//设置主题
@Override
public
void
setSubject(Subject sbj) {
this
.subject=sbj;
}
}
|
发布-订阅实例:
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
|
public
class
OBClient {
public
static
void
main(String[] args){
ConcreteSubject sbj=
new
ConcreteSubject();
ConcreteObserver obs1=
new
ConcreteObserver(
"obs1"
);
ConcreteObserver obs2=
new
ConcreteObserver(
"obs2"
);
ConcreteObserver obs3=
new
ConcreteObserver(
"obs3"
);
/**注册到主题*/
sbj.attach(obs1);
sbj.attach(obs2);
sbj.attach(obs3);
/**设置被观察对象*/
obs1.setSubject(sbj);
obs2.setSubject(sbj);
obs3.setSubject(sbj);
/**发送消息*/
sbj.postMessage(
"hello world!"
);
}
}
|
测试结果:
本文转自邴越博客园博客,原文链接:http://www.cnblogs.com/binyue/p/3728485.html,如需转载请自行联系原作者