2010-11-09 103 views
3

我需要在C++中使用事件系統。我主要有四個要求:C++事件系統設計

  1. 速度
  2. 易於使用
  3. 類型安全
  4. 友好破壞

通過「友好破壞」我的意思是事件和用戶需要管理當其中一個被破壞時,它們斷開連接:

  • 事件不應調用已銷燬的訂戶。
  • 用戶應該無法從已銷燬的事件中註銷。

我不知道是否有人會比我想出了一個更好的設計:

用戶觀點:

struct ClickEventArg {}; 

//------------------------------------------------------------------------- 
class Button 
{ 
public: 
    Event<ClickEventArg&> Clicked; 

    void SendClick(ClickEventArg& arg) 
    { 
     Clicked(this, arg); 
    } 
}; 

//------------------------------------------------------------------------- 
class User 
{ 
public: 
    void Register(Button* button) 
    { 
     button->Clicked.Subscribe(m_suscriber, this, &User::OnButtonClicked); 
    } 

    void OnButtonClicked(void* sender, ClickEventArg& arg) 
    { 
     std::cout << "button clicked"; 
    } 

private: 
    EventSubscriber m_suscriber; 
}; 

//------------------------------------------------------------------------- 
void Test() 
{ 
    Button* button = new Button(); 
    User* user = new User(); 
    user->Register(button); 
    button->SendClick(ClickEventArg()); 
    delete user; 
    button->SendClick(ClickEventArg()); 
} 

內部代碼:

class EventSubscriber; 

//------------------------------------------------------------------------- 
class BaseEvent 
{ 
public: 
    virtual void UnSubscribe(EventSubscriber& subscriber) = 0; 
}; 

//------------------------------------------------------------------------- 
template <class TEventArgs> 
class Event : public BaseEvent 
{ 
public: 
    ~Event() 
    { 
     UnSubscribeAll(); 
    } 

    typedef fastdelegate::FastDelegate2<void*, TEventArgs> EventHandler; 

    inline void operator() (void* sender, TEventArgs args) const 
    { 
     for (SubscriberMap::const_iterator it = m_subscribers.begin(); it != m_subscribers.end(); ++it) 
      it->second(sender, args); 
    } 

    template <class TClass, class TEventArgs> 
    void Subscribe(EventSubscriber& subscriber, TClass* object, void (TClass::*methodAddress)(void* sender, TEventArgs e)) 
    { 
     subscriber.Subscribe(this); 
     m_subscribers[&subscriber] = fastdelegate::MakeDelegate(object, methodAddress); 
    } 

    void UnSubscribe(EventSubscriber& subscriber) 
    { 
     subscriber.UnSubscribe(this); 
     m_subscribers.erase(&subscriber); 
    } 

    void UnSubscribeAll() 
    { 
     for (SubscriberMap::const_iterator it = m_subscribers.begin(); it != m_subscribers.end(); ++it) 
      it->first->UnSubscribe(this); 
     m_subscribers.clear(); 
    } 

private: 
    typedef std::map<EventSubscriber*, EventHandler> SubscriberMap; 
    SubscriberMap m_subscribers; 
}; 

//------------------------------------------------------------------------- 
class EventSubscriber 
{ 
    template <class TEventArgs> friend class Event; 

public: 
    ~EventSubscriber() 
    { 
     UnSubscribeAll(); 
    } 

private: 
    void Subscribe(BaseEvent* e) 
    { 
     m_subscriptions.insert(e); 
    } 

    void UnSubscribe(BaseEvent* e) 
    { 
     m_subscriptions.erase(e); 
    } 

    void UnSubscribeAll() 
    { 
     EventSet copy(m_subscriptions); 
     for (EventSet::iterator it = copy.begin(); it != copy.end(); ++it) 
     { 
      (*it)->UnSubscribe(*this); 
     } 
    } 

    typedef std::set<BaseEvent*> EventSet; 
    EventSet m_subscriptions; 
}; 

您可能請注意,我使用了本文中的快速代表http://www.codeproject.com/KB/cpp/FastDelegate.aspx

「Friendly Destruction」方面需要EventSubscriber類。 (否則我會用一個更漂亮的設計,如在C#中)

歡迎任何反饋。

謝謝。

+0

爲什麼不使用可用的庫,如Boost Signals(http://www.boost.org/doc/libs/1_44_0/doc/html/signals.html)? – 2010-11-09 05:24:31

+0

我建議在BaseEvent中添加一個虛擬(或受保護的)析構函數 – icecrime 2010-11-09 08:17:22

+0

我無法使用boost,但我會檢查它們是如何實現的。 Thx icecrime,有趣的你回答了我:) – noon 2010-11-09 17:10:34

回答