2

I am having this question when I'm using Unity with C#. But I think this question may arise in general for any OOP languages to people who are starting to learn to design OOP structures and when to use the observer pattern, or the publisher-subscriber pattern. The event I am specifically talking about is the event and delegates in C#.

I am looking for advices about using events. I am feeling event, or the Observer Pattern is so useful that I was getting afraid to be overusing it. I searched this question and found the community suggests that observer patterns is good to use to receive tweeter feeds, and that I should use the Observer Pattern if and only if using the pattern will reduce coupling. There was a discussion on when design patterns should be avoided, which suggested to prioritise to follow the SOLID principle. Some people provided a list of things to be careful about when using the observer pattern, among which commonly noted were: chains of observers and memory leaks.

The discussions seem to suggest that it is generally good to use the observer pattern when the list of subscribers for an event is expected to change at run time. For instance, RSS feeds will have different subscribers at any given time and there is no way for the programmer to know who is receiving it. So yes it seems a sweet spot to use the Observer Pattern here.

However, I still do not seem to be convinced whether I should favour of using this pattern, if the subscriber list is known to the developer at the compile time, and I want to perform Unit Testing.

Let's say in my game my character is entering a new area. Upon entering a new area, I want the game to:

Effect List

  1. Show an GUI saying The Swamp of the Code Smell in the middle of the screen
  2. Update the Quest Board to show quests specific to this area
  3. Start to decrease my character's HP 5 per second because the area has a bad smell and increase MP by 10 because it feels good to be there

To achieve this, I am not convinced which way is a better design pattern:

Approach 1: Feed all info into Constructor for Unit Testing

MapEnter class has UI, GlobalDamage, Character, ... and all required classes in its constructor. It can then just call GlobalDamage.ApplyDamagePerSecond(myCharacter), UI.ShowText(), ...

I thought of this way because a talk about Unit Test suggsted classes must be isolated and that means classes must not new any other objects, and that can be achieved only by being given the list of interactable classes through its constructor.

However, posts on how to unit test observer patterns suggest I could test to ensure (1) events are well subscribed and unsubscribed, and (2) each method to be subscribed well functions independently. So I'm not so sure of this point.

On the other hand, I also seem to believe that when a class contains all of its references as its class variables from its constructor, it's easier to understand to what extent a class is responsible for just by looking at the class variables.

Now, the problem comes when I want to extend the MapEnter's effects. Let's say in addition to the three effects I initally planned, I now want to add a new functionality to it:

Effect List:

  1. Start to play a BGM of the area

Then now, I will need to change the constructor of MapEnter class to know BgmPlayer. Change its implementation on OnMapEnter(). Change Unit Test Cases. And so on and so forth.

This may enable Unit Test but is strongly tied with other classes and so it appears to have high coupling.

Approach 2: Publisher-Subscriber Pattern

A big plus of this approach is that now it is super easy to add any new ideas to MapEnter. It's as easy as adding lines of code to add/remove methods to the event. MapEnter now need not worry about taking N parameters in its constructor.

Here I'm applying the Observer Pattern even though I know exactly who are going to listen to this event at the compile time, which means I could indeed achieve this without using the observer pattern here.

My concerns are:

  1. Does this reduce coupling? Is it good to use the observer pattern in this kind of cases?
  2. Does the Unit Test Argument in Approach 1 justify Approach 1?
  3. Wouldn't it be easier to understand the code structure if a class has all references to what it needs to call as in Approach 1? If other programmers in my team silently added new subscribers to the event of MapEnter, how would I know that without going through all of the event's references? Or is it expected that I should do so for every single event in my application when things go wrong?

If I am justified to use the observer pattern here because it reduces coupling, literally all methods could, and should, be invoking other methods by events, as long as the listeners do not care about who is called first and there is no chains of observers. Then this pattern will be everywhere, and that sounds like it's going to be painful to understand the code even if I ensure there is only 1 or 2 levels of observer chains.

Thanks in advance.

Community
  • 1
  • 1
Matt
  • 1,424
  • 1
  • 13
  • 17

1 Answers1

1

Decision depends of your situation, I think it is important to understand difference beteeen Observer and Publisher/Subscriber patern.

Observer is mostly implemented in a synchronous way where the observable calls the appropriate method of all its observers when some event occurs. The Publisher/Subscriber pattern is mostly implemented in an asynchronous way (via message queue).

In the Observer/Observable pattern, the observers are aware of the observable. Whereas, in Publisher/Subscriber, publishers and subscribers don't need to know each other. They simply communicate with the help of message queues.

dstar55
  • 938
  • 6
  • 11
  • Thanks for pointing out the difference between the two patterns. However, i was more concerned as to whether it is justifiable to feed all info into the parameters of the constructor, which would make it harder to add features later on IMHO. You said "Decision depends on your situation." Could you elaborate further on what would be the best approach in this particular scenario, and why? I seem to lack of experience to determine what are the factors that I should care about and how they will affect my decisions. – Matt Apr 21 '17 at 06:32
  • @Matthias, I am not aware how implementation of the Observer looks like in your case, but if you check referent implementation(http://www.design-patterns-stories.com/patterns/Observer/), than I do not see need for "injecton" of the parameters in constructor. Observers can be attached/detached to Subject. On other side I am not aware do you need synch or asynch response in order to decide between Observer & Publisher/Subscriber – dstar55 Apr 21 '17 at 07:24