5

Take the following basic structured code for example:

class Player
{
   public QuestLog QuestLog { get; set; }
}

Let us consider that "QuestLog" has the ability to fire off some events when things are added or removed from it. Normally, I would subscribe directly to the QuestLog, such as doing something like:

player.QuestLog.AcceptedQuest += SomeHandler

However, I want to pass in some extra context (the player object). I saw a couple options.

  1. Creating a lambda handler function which can resolve an extra parameter to the handler. This works but has some quirks I don't like. I'm currently using this approach.
  2. I could couple the QuestLog to a Player, passing a reference of the player it belongs to in and fire events off accordingly with it. Feels like needless coupling.
  3. Expose the event on the Player object itself as well as the QuestLog and 'bubble' the event up into where the context is available, thus allowing subscriptions directly onto player.

Keep in mind a player may have a few collections and a few events, so moving them all up might cause a couple dozen events to be held on one class.

How is this usually handled?

  • Increasingly, by not using events. – Telastyn Aug 26 '14 at 23:46
  • My architecture is pretty event-driven. I'm open to suggestions, though. What are other good ways to send notifications? – Vaughan Hilts Aug 26 '14 at 23:46
2

Creating a lambda handler function which can resolve an extra parameter to the handler. This works but has some quirks I don't like. I'm currently using this approach.

What don't you like? By keeping the signature small, and letting the handler be aware of the things it needs (but the event firing object needs to not know) you very effectively separate knowledge to where it needs to go.

I could couple the QuestLog to a Player, passing a reference of the player it belongs to in and fire events off accordingly with it. Feels like needless coupling.

Since players already have QuestLogs, then I'd argue that the coupling already exists to some degree. Further, if your handler wants to know that, that just reinforces that notion.

Coupling isn't always bad. Some things really should depend on one another and a clean design will couple those things together cohesively so that it's simple, clean, and robust.

Expose the event on the Player object itself as well as the QuestLog and 'bubble' the event up into where the context is available, thus allowing subscriptions directly onto player.

Sometimes good, but often a sign that you've got the event in the wrong place. This leaks implementation details (or at least it would if you didn't have QuestLog on the player publically, encouraging users to violate the Law of Demeter...).

But getting back to my comment, events have largely fallen out of favor for doing non-UI logic. Events, by their nature cause temporal coupling (you need to do things at the right time, in the right order for them to work properly). Events protect invariants poorly, and tend to leak through abstractions. They're fragile, they're fairly hard to test, they require some mediator to add/remove the event, they're the primary cause of memory leaks...

More often, delegates (or the dependencies themselves) are passed directly into the constructor so that the handler is known at construction time. You can't misuse the class if it's built to work from the start.

That or things work on a pull rather than push mechanism. Something checks the state every frame or some other timeframe (optionally checking some dirty flag which is pushed). This makes it easier to ignore the timing of things in many cases, making parallelism much more viable.

  • Slightly off topic -- but could you tell me why it's bad to expose the 'QuestLog'? It seemed clean to me but maybe I'm off my rocker. :) – Vaughan Hilts Aug 27 '14 at 2:19
  • @VaughanHilts - see the Law of Demeter. It can be appropriate, but more often it's making the player do more than it should. – Telastyn Aug 27 '14 at 2:24
  • Interesting -- player owns the QuestLog (it created it) so it seems like it wouldn't violate LoD, though. I'll give some research. – Vaughan Hilts Aug 27 '14 at 2:37
  • @VaughanHilts - it doesn't, but by exposing it publically, it invites others to violate it. – Telastyn Aug 27 '14 at 2:44

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.