1
\$\begingroup\$

I am wondering how I implement an observer pattern in the following example. I am mostly wondering what should be in charge of subscribing.

The Example

A factory produces cars (Observable), they drive from A to B. Once at B the car has finished. The scoreboard increases by +1 (Observer).

The Solution?

Option A.) The factory spawns a car, it then calls a method to subscribe the car to the scoreboard

observableCar.FinishedEvent += observerScoreboard.HandleEvent;

Option B.) Should the cars on being created register / tell the the scoreboard to subscribe itself to it the cars finishedEvent()

this.FinishedEvent += observerScoreboard.HandleEvent;

Option C.) The scoreboard is subscribed to a 'carSpawned' event on the factory. On recieving this event it then subscribes itself to the cars finishedEvent(). It then unsubscribes.

Option D.) I am missing something fundamental about the observer pattern, do more homework

I'm thinking its something more akin to option C? I'm not sure.

Thanks very much

Jim

\$\endgroup\$
1
\$\begingroup\$

First of all, any of the three options is a valid solution. There is never just one right way to do something in software engineering.

However, I would recommend the option which results in the least coupling between car and scoreboard. Loose coupling means the less objects need to know about other objects, the better. In the ideal case, they would not even know that objects exist which are not relevant to their primary functionality. An event system is a great way to achieve loose coupling, because objects are able to post events without knowing anything about which objects are going to process them.

Another concern is trying to always do things the same way. Who is responsible in your system for subscribing and who is responsible for unsubscribing? The sender, the receiver or a middle-man? Whichever convention you pick, it can be useful to try to stick to it throughout your code-base. Otherwise you might get confused about when and where you set up your subscriptions and end up subscribing to something twice or not at all.

Option A: A factory is one of the few classes where tight coupling with its product can not be avoided. That's why factories exist. So the logic for setting up event subscriptions fits there quite well. But the question is, does the car factory need to be coupled to the existence of the scoreboard? What if you add more things which process car-related events? Does the factory really need a dependency on every one of these features?

Option B: Do the cars need to know that the scoreboard exist? If they know about the scoreboard, they would also be able to notify it by itself when it finished the race. You wouldn't need that detour via the event system in the first place. So cars shouldn't register themselves to the scoreboard. I would in fact try to make them completely oblivious to the existence of the scoreboard. I haven't seen your Car-class, but when it's the main game-object your game is about, it's quite likely already has more than enough responsibilities. Anything you can move somewhere else will likely keep it from mutating into a bloated god-object.

Option C: This option is the one I personally like best. The factory doesn't know about the scoreboard (it just knows something subscribed to carSpawned) and the car doesn't know about the scoreboard (just that something subscribed to carFinished). The only thing I don't like about it is that there is no clear concept of for who is responsible for setting up subscriptions. carSpawned is subscribed by the sender and carFinished is subscribed by the receiver.

Unfortunately there is no perfect solution to this conundrum. Objects don't exist in limbo. To glue two objects together with event subscriptions, there must be some object which knows both of them.

A solution which I prefer is having objects communicate only through a global EventSystem object. Observers don't subscribe to Observables, they subscribe for a specific event on the eventSystem. Observables don't post events to their Observers directly, they post them to the eventSystem. The eventSystem is then responsible for routing events to every object which subscribed to them. Such a system usually scales pretty well, because new features can often be added by simply using already existing events without having to do any changes at the objects which already send/receive them. However, for games with a very limited scope, such an event system can be overengineering. It also adds a layer of indirection which can make debugging harder and can cause performance problems when you overuse it.

\$\endgroup\$
  • \$\begingroup\$ Thanks very much for your comprehensive answer. I really like your solution of creating an eventsystem, do you have any recommendations for where I can go to read more / tutorials? \$\endgroup\$ – Jim Sep 23 '17 at 15:38
  • \$\begingroup\$ nevermind found it ! unity3d.com/learn/tutorials/topics/scripting/… \$\endgroup\$ – Jim Sep 23 '17 at 15:40

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.