2012-03-22 56 views
1

我正在創建一種機制,通過該機制,接收者可以告訴發件人每個Receiver對某種類型的消息感興趣。與我的樣本實現下面存在一個限制,其中想要接收器接收的某些基本類型僅接收是該類型的顯式和的郵件將不會收到派生類型的消息(見主所有消息()例如)。如何查找對象祖先的類型?

的潛在解決方案將是登記該特定消息時,註冊所有消息的祖先的類型,正確使用這些信息來路由消息。

有沒有什麼其他的解決方案?

注:在現實中,我會保存RTTI所以RTTI查找不會每次都需要。還有其他的東西,我也在這裏掠過/跳過。我要爲簡潔瓦特/這個例子......下面

示例代碼:

class Sender 
{ 
    typdef std::vector<Receiver const & > Receivers; 
public: 
    void register(Receiver const & i_recv, typeinfo const & i_type) 
    { 
    m_routingMap[i_type].push_back(i_recv); 
    } 


    void send(BaseMsg const & i_msg) 
    { 
    Receivers receivers = m_routingMap.find(typeid(i_msg)); 
    for (Receivers::iterator receiver = receivers.begin(); receiver != receivers.end(); ++receiver) { 
     receiver.receive(i_msg); 
    } 
    } 

private: 
    std::map<typeinfo const &, Receivers> m_routingMap; 
}; 


class Receiver 
{ 
public: 
    void receiver(BaseMsg const & i_msg) 
    { 
    // React to expected messages here 
    } 
}; 


class BaseMsg {}; 

class ChildMsg : public BaseMsg {}; 

int main() 
{ 
    Sender sndr; 

    Receiver recv1; 
    sndr.register(recv1, typeid(BaseMsg)); 

    Receiver recv2; 
    sndr.register(recv2, typeid(ChildMsg)); 

    BaseMsg baseMsg; 
    sndr.send(baseMsg); // I want only recv1 to receive this message 

    ChildMsg childMsg; 
    sndr.send(childMsg); // I want both Receivers to receive this message, but only recv2 will receive it 
} 

更新:這是我得到了一個解決方案:

// Note: implementation is based in gleaning from 
// http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14 

class BaseMsg 
{ 
public: 

    typedef std::vector<TypeInfo const & > Types; 

    static TypeInfo const * getType() 
    { 
    TypeInfo static * ms_type = new TypeInfo(typeid(BaseMsg)); 
    return ms_type; 
    } 

    static Types const * getAncestorTypes() 
    { 
    // The base class does not have an ancestor 
    // Static varible, will only be constructed once! 
    Types * ms_ancestorTypes = new Types(); 
    return ms_ancestorTypes; 
    } 
}; 


class ChildMsg 
{ 
public: 
    static TypeInfo const * getType() 
    { 
    TypeInfo static * ms_type = new TypeInfo(typeid(ChildMsg)); 
    return ms_type; 
    } 

    static Types const * getAncestorTypes() 
    { 
    // Add the parent type and all the parent's ancestor's types 
    Types const * ancestorTypes = BaseMsg::getAncestorTypes(); 

    // Static variable, so it will only be constructed once! 
    Types * static ms_ancestorTypes = new Types(ancestorTypes->begin(), ancestorTypes->end()); 

    // This push_back() will occur every time, but it's only one operation, 
    // so hopefully it's not a big deal! 
    ms_ancestorTypes->push_back(BaseMsg::getType()); 

    return ms_ancestorTypes; 
    } 
}; 

和發件人:

# Python pseudo code 
class Sender: 
    def send(self, i_msg): 
    types_to_check_for = [i_msg.getType()].extend(i_msg.getAncestorTypes()) 

    for type_ in types_to_check_for: 
     for receiver in _routing_list[type_]: 
     receiver.receive(i_msg) 

回答

0

也許考慮使用觀察者模式(http://en.wikipedia.org/wiki/Observer_pattern)。

這樣,你發送者沒有你的接收器的知識,你的觀察者可以控制Msgs的分佈。

發件人 - >通知觀察者有一條消息。

觀察員 - >通知各利害關係方有一個新的味精。

感興趣的部分 - >確實有趣的東西。

這將需要某種味精鑑定系統。也許所有的消息都可以從具有類型成員和id成員的msg類型繼承。這樣你可以使用它們註冊消息。

更新:

快速MSG結構:

class Message 
{ 
public: 
    size_t m_Type; 
    size_t m_Id; 

protected: 
    Message(size_t type, size_t id) : m_Type(type), m_Id(id) {} 
}; 

class Type1 : public Message 
{ 
public: 
    static const size_t type = 1; 
    Type1(size_t id) : Message(type, id) {} 
}; 

訂戶意味着要聽MSG)的人。用戶應該有一個接口來接受基於這兩種功能的消息。

Class subscriber 
{ 
    virtual void receiveType(size_t type, char * data) = 0; 
    virtual void receiveMsg(size_t type, size_t id, char * data) = 0; 

}; 

觀察員應該有一個方法,爲封郵件註冊:

Class Observer 
{ 
void registerForType(type, subscriber); 
void registerForMsg(type, id, subscriber); 
}; 

另一個更新:

這真的只是一個粗略驗證的概念。不知道確切的祖先鏈,人們可以做你想做的事。原諒觸發器和registrationEntry函數的切換(我起初做錯了,那是最簡單的修正,再次證明了概念)。這個草圖的另一個缺點是,至少必須構造一個味精才能進行註冊。如果你正在尋找一個真正的長期解決方案,我建議你找一個已經有反射的庫或框架(例如QT有元對象),這些可以用來看超類。或者,您可以使用已經存在的信號/插槽。從下面的代碼

輸出:

開始C:\用戶\大衛\下載\ ASDF-集結桌面Qt_4_8_0_for_Desktop_- MinGW的 _Qt_SDK__Release \發佈\ asdf.exe ...
基址寄存器
註冊:BaseMsg
兒童註冊
註冊:消息
基地呼叫
觸發:BaseMsg
虛擬無效認購1 :: newMessage(const BaseMsg &)
Der。調用
觸發:BaseMsg
虛擬無效Subscriber1的:: NewMessage作爲(常數BaseMsg &)
觸發:消息
虛擬無效subscriber2用戶:: NewMessage作爲(常數BaseMsg &)
C:\ Users \用戶大衛\下載\ asdf-集結桌面Qt_4_8_0_for_Desktop_- MinGW的 _Qt_SDK__Release \發佈\ asdf.exe退出,代碼爲0

#include <string> 
#include <vector> 
#include <map> 
#include <stdio.h> 
using namespace std; 

class BaseMsg 
{ 
public: 
    BaseMsg() 
    { 
     theRealInit(); 
    } 

    //incase you don't want to go all the way down the rabbit hole. 
    //At the bottom they are the same 
    virtual vector<string> const & registrationEntries() const {return m_SubClassChain;} 
    virtual vector<string> const & triggerEntries() const  {return m_SubClassChain;} 

    protected: 
    virtual void init() { printf("Should NOT CALL THIS HERE!");} 
    vector<string> m_SubClassChain; 

private: 

    void theRealInit() 
    { 
     m_SubClassChain.push_back("BaseMsg"); 
    } 


}; 

class Message : public BaseMsg 
{ 
    public: 
    Message() : BaseMsg() 
    { 
     init(); //MUST BE CALLED from child 
    } 

    virtual vector<string> const & triggerEntries() const  {return m_TriggerEntries;} 

protected: 
    virtual void init() 
    { 
     //BaseMsg::init(); 
     m_SubClassChain.push_back("Message"); 
     m_TriggerEntries.push_back("Message"); 
    } 

private: 
    vector<string> m_TriggerEntries; 
}; 

class Subscriber 
{ 
public: 
    virtual void newMessage(BaseMsg const & i_msg) 
    { 
     printf("%s\n", __PRETTY_FUNCTION__); 
    } 
}; 

class Subscriber2 : public Subscriber 
{ 
public: 
    virtual void newMessage(BaseMsg const & i_msg) 
    { 
     printf("%s\n", __PRETTY_FUNCTION__); 
    } 
}; 

class Subscriber1 : public Subscriber 
{ 
public: 
    virtual void newMessage(BaseMsg const & i_msg) 
    { 
     printf("%s\n", __PRETTY_FUNCTION__); 
    } 
}; 



class Sender 
{ 
    //typdef vector<Receiver const & > Receivers; 
public: 

    void registerForMsg(Subscriber * someoneThatCares, BaseMsg const & msg) 
    { 
     vector<string> const & triggers = msg.triggerEntries(); 

     vector<string>::const_iterator it = triggers.begin(); 
     for(; it != triggers.end(); it++) 
     { 
      printf("Registration: %s\n", it->c_str()); 

      m_routingMap.insert(pair<string, Subscriber *>(*it, someoneThatCares)); 
     } 
    } 


    void send(BaseMsg const & msg) 
    { 
     vector<string> const & triggers = msg.registrationEntries(); 
     vector<string>::const_iterator it = triggers.begin(); 
     for(; it != triggers.end(); it++) 
     { 

      printf("Trigger: %s\n", it->c_str()); 
      pair<multimap<string, Subscriber *>::iterator, multimap<string, Subscriber *>::iterator> ret; 

      //borrowed from: http://www.cplusplus.com/reference/stl/multimap/equal_range/ 
      ret = m_routingMap.equal_range(*it); 

      multimap<string, Subscriber *>::iterator it1; 
      for (it1 = ret.first; it1 != ret.second; ++it1) 
      { 

       it1->second->newMessage(msg); 
      } 
     } 
    } 

private: 
    multimap<string, Subscriber *> m_routingMap; 
}; 

int main(int argc, char *argv[]) 
{ 
    Sender sndr; 

    BaseMsg baseMsg; 
    Message message; 

    printf("Base Register\n"); 
    Subscriber1 recv1; 
    sndr.registerForMsg(&recv1, baseMsg); 

    printf("Child Register\n"); 
    Subscriber2 recv2; 
    sndr.registerForMsg(&recv2, message); 


    printf("Base call\n"); 
    sndr.send(baseMsg); // I want only recv1 to receive this message 

    printf("Der. call\n"); 
    sndr.send(message); // I want both Receivers to receive this message, but only recv2 will receive it 

    return 0; 
} 
+0

我的職位是需要的信息識別系統。 – 2012-03-22 20:01:27

+0

請注意:此代碼未編譯,僅作爲示例。 – 2012-03-22 20:34:37

+0

這並沒有解決我試圖解決的特定問題。請參閱我的main()以查看相關問題。 – 2012-03-22 23:27:29