Design Patterns – Communicating Between Unrelated Components

designdesign-patternsobject-oriented

Imagine that I have a game, with Monsters, Missions, Vehicles, and of course their controllers and such, so a Monster class, Mission Controller class, Vehicle Controller class and so on.

Suppose that I need the Mission Controller to talk to Monsters. Why? Let's say when Mission A is triggered, all Monsters now turns color blue, from their original color.

There are many ways to let the Mission Controller talk to the Monster class. One way is to use the Observer pattern. The MissionController would add the Monster to its list of observers, and when the MissionController changes Missions, it tells the Monster using ONMISSIONCHANGED() or something.

The problem with that approach is why should the Monster care about MissionController? Shouldn't Monster not even know that MissionController exist? Suppose that one day, we don't want the Monster to change color, we want vehicles to do it, then we have to get rid of Monsters from the list of observers, reimplement the same thing in Vehicles and add Vehicles to the list, isn't that tedious?

Another approach is to use Singletons, there is some almighty class that has a pointer to Monsters, Vehicles, whatever. And the MissionController can just get a reference to the Monster Class immediately. But Singletons are bad, and just making Singletons for communicating between missions and monsters is just another hack.

My question is then, if the MissionController wants to set/get a property of Monster, how would it do it? How can I avoid Monster from knowing about MissionController, but yet tell the MissionController about Monster?

TL:DR – How do you allow communication between two completely unrelated objects, if you don't want them to know about each other, AND not use the Observer pattern?

EDIT:

So it seems that the idea is to use Mediator and messages, create a Mediator class, call it MissionCommunicator, and it has a list of observers where one of it would be the monster. When the MissionController wants to talk to the outside, MissionCommunicator would pass that message to the outside through IMissionMessage interface or something.

In that case, then Monster would have to implement IMissionMessage to listen to that message.

Now, imagine we have MissionController, VehicleController, AchievementController, AnimalController, etcetera…..

Suppose for some reason, Monster, for the same reason that it needs to talk to MissionController, will have to talk to all those other ones as well.

If we let Monster communicate using mediators, now we have to make a mediator for Vehicle, Achievement, Animal, blahblahblah

and Monster class becomes this:

Class Monster Implements IMissionMessage, IAchievementMessage, IAnimalMessage…..

You can of course use interface inheritance to deal with this, make a parent IMessage interface subclassing those IMissionMessage interfaces if you are using Java.

But what would be a better solution?

Best Answer

In the example you give (mission controller turns monsters blue), you wouldn't need communication between the controller and the monsters. Instead the monsters could look up the "monster color" in a palette (or color table). The mission controller just sets a different value for "monster color" in the palette when the mission changes. Or switch the entire palette if the mission change affects not only monsters ...

Call the palette a style sheet and you will get the idea that a mission change will be able to change more than just colors ...

However for your other question:

How do you allow communication between two completely unrelated objects, if you don't want them to know about each other, AND not use the Observer pattern?

In my opinion, the best way to achieve this is via events, i.e. in your example:

  • the monsters are subscribed on an event channel for the 'mission change event'
  • the controller issues a 'mission change event' on the event channel, and
  • the monsters change their color when they receive the 'mission change event'

That way both controller and monsters don't have to know about each other. However, both have to know about the (same) 'mission change event' and the (same) event channel.

To achieve a more decoupled design, you could also combine this with the palette approach described above as follows:

  • a palette (or style sheet) manager is subscribed on an event channel for the 'mission change event'
  • the controller issues a 'mission change event' on the event channel, and
  • the manager switches to a different palette (or style sheet) on receiving the 'mission change event'; the palette is chosen based on information transported in the event ...