1. 程式人生 > >設計模式之觀察者2

設計模式之觀察者2

COCOS2D-X中的觀察者

在cocos2d-x中被觀察者是NotificationCenter,但它不是通過自身狀態改變來通知觀察者,而是通過顯示地傳送觀察者感興趣的訊息(postNotification)來通知它們。每一種訊息型別可以對應多個觀察者,同時,每一個觀察者也可以“觀察”多個訊息型別。其次,觀察者定義相應的響應事件同訊息型別關聯,當某個地方觸發postNotification來廣播一個訊息的時候,NotificationCenter會遍歷所有的觀察者,判斷它們註冊的訊息型別是否匹配,如果匹配,則觸發相應的註冊響應事件。最後,該觀察者模式採用的是推模型,即由目標物件去通知所有的觀察者。 其實NotificationCenter和NotificationObserver更準確的叫法是:訂閱釋出模式。

觀後感

CCNotificationObserver相當於一個組裝器,把object(物件)、func(物件的方法)、name(事件)組裝到一起,變成一個Observer實體。 CCNotificationCenter中封裝了一個CCArray容器,同一個物件、不同事件可以當做不同的Observer新增,總之,是以event來區別不同的觀察者而不是object。

例項

//新增觀察者
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);
};