设计模式之观察者模式

什么是观察者

一个目标对象可以注册多个观察者,当目标对象的状态改变的时候,可以通知观察者对象作出相应的响应。这是标准的观察者模式的实现。 观察者模式又称为发布-订阅模式。


优缺点

优点:

- 实现了目标对象和观察者之间的抽象耦合,在本例中,则是实现了消息与观察者的抽象耦合。可以定义一种消息与消息处理对象的一对多的关系,而不用担心彼此的实现细节。

缺点:

- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。


适用场合

一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。

一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。

一个对象必须通知其他对象,而并不知道这些对象是谁。需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

JAVA实现

采用发布-订阅模式,例如报社(被观察者)有很多订阅者(观察者),每天的早晨有新报纸就通知所有的订阅者。

QQ截图20141218131056.png

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);
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值