Note that there are some explanatory texts on larger screens.

plurals
  1. POPros and cons of a centralized event dispatch
    primarykey
    data
    text
    <p>I'm considering different approaches to implementing events in a C++ application. There's a suggestion to implement a centralized event dispatch, via a notification center. An alternative would be for sources and targets of the events to communicate directly. I'm having reservations about the notification center approach, however. I'll outline both approaches as I see them (I could well be misunderstanding something about them, I've never implemented event handling before).</p> <p>a) Direct communication. Events are a part of their source's interface. Objects interested in the event must somehow get a hold of an instance of the source class and subscribe to its event(s):</p> <pre><code>struct Source { Event&lt;/*some_args_here*/&gt; InterestingEventA; Event&lt;/*some_other_args_here*/&gt; InterestingEventB; }; class Target { public: void Subscribe(Source&amp; s) { s.InterestingEventA += CreateDelegate(&amp;MyHandlerFunction, this); } private: void MyHandlerFunction(/*args*/) { /*whatever*/ } }; </code></pre> <p>(From what I understand, boost::signals, Qt signals/slots and .NET events all work like this, but I could be wrong.)</p> <p>b) Notification center. Events aren't visible in their source's interface. All events go to some notification center, probably implemented as a singleton (any advice on avoiding this would be appreciated), as they are fired. Target objects don't have to know anything about the sources; they subscribe to certain event types by accessing the notification center. Once the notification center receives a new event, it notifies all its subscribers interested in that particular event.</p> <pre><code>class NotificationCenter { public: NotificationCenter&amp; Instance(); void Subscribe(IEvent&amp; event, IEventTarget&amp; target); void Unsubscribe(IEvent&amp; event, IEventTarget&amp; target); void FireEvent(IEvent&amp; event); }; class Source { void SomePrivateFunc() { // ... InterestingEventA event(/* some args here*/); NotificationCenter::Instance().FireEvent(event); // ... } }; class Target : public IEventTarget { public: Target() { NotificationCenter::Instance().Subscribe(InterestingEventA(), *this); } void OnEvent(IEvent&amp; event) override {/**/} }; </code></pre> <p>(I took the term "Notification center" from Poco, which, as far as I understand, implements both approaches).</p> <p>I can see some pros to this approach; it will be easier for the targets to create their subscriptions because they wouldn't need access to the sources. Also, there wouldn't be any lifetime management problems: unlike sources, the notification center will always outlive the targets, so they targets always unsubscribe in their destructors without worrying whether the source still exists (that's a major con I can see in the direct communication). However, I am afraid that this approach could lead to unmaintainable code, because:</p> <ol> <li><p>All sorts of events, probably completely unrelated to each other, would go to this one big sink.</p></li> <li><p>The most obvious way of implementing the notification center is as a singleton, so it will be hard to track who and when modifies the subscribers' list.</p></li> <li><p>Events aren't visible in any interface, so there is no way to see whether a particular event belongs to any source at all.</p></li> </ol> <p>As a result of these cons, I'm afraid that as the application grows it would become very difficult to track connections between objects (I'm imagining problems trying to understand why some particular event doesn't fire, for example).</p> <p>I'm looking for advice regarding the pros and cons of the "notification center" approach. Is it maintainable? Does it fit every sort of applications? Maybe there are ways to improve the implementation? Comparison between the two approaches I described, as well as any other event handling suggestions, are most welcome. </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload