0
\$\begingroup\$

Does anyone know what Nystrom meant in this excerpt from http://gameprogrammingpatterns.com/observer.html?

enter image description here

I created an example implementation of the observer pattern in c++ from my medal system.

I am wanting to pass my KillType enum to onNotify without muddling up the base Observer/Subject classes with that level of specifics.

My Medals class needs to know specifics about what type of kill it was so it can award the appropriate medal (ex. Headshot).

Does anyone know of a way to use templates to do this? Or what is a good way to get that level of detail from PlayerState to Medals?

The first thing I thought of was to use polymorphism and an Event class with a bunch of subclasses for each type. But that seems really class heavy to me to just pass some variables around.

Runnable Example

\$\endgroup\$
  • \$\begingroup\$ At the receiving end you'd still need to check what event type it actually is. Unless you create observer objects for different events that have specific parameter implementations. In C# you can derive from a base class to notify objects, but this way you're still casting at the receiving end. I'm not too sure about templates but it does imply that the receiving end needs to match the type passed into the generic. If I'm wrong someone please correct me. \$\endgroup\$ – Sidar Jul 25 '17 at 17:58
3
\$\begingroup\$

It makes sense to have your basic Observer and Subject implementations unaware of higher level data types, but at some point they have to commit to a common contract to be able to communicate.

You may just have a void* to pass event data which the observer has to cast based on the type of event, but I prefer to be explicit about my types.

It's years since I've done C/C++ but I've played with your code and this is what I've come up with:

  • I've made templates from your Observer and Subject base implementations, for which you need to specify the data types of the event and the event data, like template<class EventType, class DataType> class Observer
  • I changed Medals and PlayerState so that they specify the event types of their base classes to be of type Event and the event data type to be of new type EventData, like class Medals : public Observer<Event, const EventData &>
  • EventData holds any data that Event-handlers might require, like the type of kill made, or current ingame time or whatever.

This way the base implementations are unaware of specific data types, while your concrete implementations are type safe and have a common contract, specifically: "Observers of PlayerState will be notified with two parameters of type Event and const EventData &".

See https://wandbox.org/permlink/XLBXE0qNGqZScZwu for the final implementation.

\$\endgroup\$
  • \$\begingroup\$ This is the perfect answer, thank you Thomas for taking the time to list everything you changed and the reasoning behind it. Seriously this is amazing. So in the future, to pass new properties to support different medals, I would just add a new property to EventData and then create a new EventData constructor to support it? That should be the last thing that would be beneficial to see. \$\endgroup\$ – erebel55 Jul 26 '17 at 15:13
  • 2
    \$\begingroup\$ Indeed that's what I tried to explain in bulletpoint #3: Observers of PlayerState want to handle events of type Event. Anything they need to know to handle them should be put into EventData. And that's not exclusive to Medals, you can have different Observers for anything you might want to do when events happen on PlayerState. How to design your constructors is completely your choice and not covered by the pattern. \$\endgroup\$ – Thomas Hilbert Jul 26 '17 at 15:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.