什么是观察者
一个目标对象可以注册多个观察者,当目标对象的状态改变的时候,可以通知观察者对象作出相应的响应。这是标准的观察者模式的实现。 观察者模式又称为发布-订阅模式。
优缺点
优点:
- 实现了目标对象和观察者之间的抽象耦合,在本例中,则是实现了消息与观察者的抽象耦合。可以定义一种消息与消息处理对象的一对多的关系,而不用担心彼此的实现细节。
缺点:
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
适用场合
一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
一个对象必须通知其他对象,而并不知道这些对象是谁。需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
JAVA实现
采用发布-订阅模式,例如报社(被观察者)有很多订阅者(观察者),每天的早晨有新报纸就通知所有的订阅者。
Office.java:报社
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
interface Office {
//添加观察者
public
void
addObserver(People p);
//删除观察者
public
void
deleteObserver(People p);
//通知所有的观察者
public
void
notifyObservers(String msg);
}
People.java:人
public
interface People {
//收到来自观察者的消息
public
void
update(String msg);
}
|
BrightOffice.java:光明日报
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public
class
BrightOffice {
//所有观察者的集合
private
ArrayList<People> peopleList =
new
ArrayList<People>();
public
void
addObserver(People p) {
this
.peopleList.add(p);
}
public
void
deleteObserver(Observer o) {
this
.peopleList.
remove
(o);
}
public
void
notifyObservers(String msg) {
for
(People p : peopleList) {
p.update(msg);
}
}
//通知
public
void
publish() {
this
.notifyObservers(
"今天出新报纸啦!"
);
}
}
|
OldPeople.java:老人
1
2
3
4
5
6
|
public
class
OldPeople implements People{
public
void
update(String msg) {
System.out.println(msg);
System.out.println(
"我要去取今天的新报纸啦!"
);
}
}
|
Test.java:测试程序
1
2
3
4
5
6
7
8
|
public
class
Test {
public
static
void
main(String[] args) {
People p1 =
new
OldPeople();
BrightOffice brightOffice =
new
BrightOffice();
brightOffice.addObserver(p1);
brightOffice.publish();
}
}
|
Cocos2d-x中的观察者
在Cocos2d-x中被观察者是NotificationCenter,但它不是通过自身状态改变来通知观察者,而是通过显示地发送观察者感兴趣的消息(postNotification)来通知它们。每一种消息类型可以对应多个观察者,同时,每一个观察者也可以“观察”多个消息类型。其次,观察者定义相应的响应事件同消息类型关联,当某个地方触发postNotification来广播一个消息的时候,NotificationCenter会遍历所有的观察者,判断它们注册的消息类型是否匹配,如果匹配,则触发相应的注册响应事件。最后,该观察者模式采用的是推模型,即由目标对象去通知所有的观察者。 其实NotificationCenter和NotificationObserver更准确的叫法是:订阅发布模式。
观后感
CCNotificationObserver相当于一个组装器,把object(对象)、func(对象的方法)、name(事件)组装到一起,变成一个Observer实体。 CCNotificationCenter中封装了一个CCArray容器,同一个对象、不同事件可以当做不同的Observer添加,总之,是以event来区别不同的观察者而不是object。
实例
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
|
//添加观察者
CCNotificationCenter::sharedNotificationCenter()->addObserver(
this
, callfuncO_selector(HelloWorld::myNotification),
"MY_NOTIFICATION"
, NULL);
/** 一般的在接受通知的一方在接受完通知后需要remove监听。
(注意第二个方法: returns the number of observers removed)*/
void
removeObserver(CCObject *target,
const
char
*name);
int
removeAllObservers(CCObject *target);
//事件名字
CCNotificationCenter::sharedNotificationCenter()->postNotification(
"MNOTIFICATION"
, (CCObject*)1);
CCNotificationCenter.h
/**
* @js NA:不适用
* @lua NA:不适用
*/
//观察者
class
CC_DLL CCNotificationObserver :
public
CCObject
{
public
:
/** @brief 构造一个观察者
* @param target 想做观察者的对象
* @param selector 回调方法
* @param name 消息名字
* @param obj 将被传递给回调函数的额外参数
*/
CCNotificationObserver(CCObject *target,
SEL_CallFuncO selector,
const
char
*name,
CCObject *obj);
/** 释放成员 */
~CCNotificationObserver();
/** target通过回调方法调用obj */
void
performSelector(CCObject *obj);
private
:
/** 定义CCObject类型的对象m_target,并创建一个getTarget方法 */
CC_PROPERTY_READONLY(CCObject *, m_target, Target);
CC_PROPERTY_READONLY(SEL_CallFuncO, m_selector, Selector);
CC_PROPERTY_READONLY(
char
*, m_name, Name);
CC_PROPERTY_READONLY(CCObject *, m_object, Object);
//创建get和set方法
CC_PROPERTY(
int
, m_nHandler,Handler);
};
//被观察者
class
CC_DLL CCNotificationCenter :
public
CCObject
{
private
:
//判断是否存在name名字的target
bool
observerExisted(CCObject *target,
const
char
*name);
//观察者集合
CCArray *m_observers;
//lua专用
int
m_scriptHandler;
public
:
/** 构造函数,初始化集合m_observers */
CCNotificationCenter();
/** 释放集合m_observers */
~CCNotificationCenter();
/** 获取单例对象 */
static
CCNotificationCenter *sharedNotificationCenter(
void
);
/** 销毁单例对象 */
static
void
purgeNotificationCenter(
void
);
/** 添加观察者
* @param target 观察者
* @param selector 观察者的回调方法
* @param name 通知消息
* @param 传给回调方法的额外参数
*/
void
addObserver(CCObject *target,
SEL_CallFuncO selector,
const
char
*name,
CCObject *obj);
/** @brief 移除指定name的target
* @param target The target of this notification.
* @param name The name of this notification. */
void
removeObserver(CCObject *target,
const
char
*name);
/** @brief 移除这个target的所有观察者
* @param target.
* @returns 返回被移除观察者的数量 */
int
removeAllObservers(CCObject *target);
/** lua脚本中使用的注册、注销观察者*/
void
registerScriptObserver(CCObject *target,
int
handler,
const
char
* name);
void
unregisterScriptObserver(CCObject *target,
const
char
* name);
/** 执行指定name的观察者的回调方法 */
void
postNotification(
const
char
*name);
void
postNotification(
const
char
*name, CCObject *object);
/** 获取脚本的回调方法 */
inline
int
getScriptHandler() {
return
m_scriptHandler; };
int
getObserverHandlerByName(
const
char
* name);
};
|