When many objects in code need to interact with each other, it's easy for spaghetti code to rear its ugly head. One way to avoid this referential clutter is by having all the objects pass data to a single place called a Mediator.

Assumptions

What is the Mediator Pattern?

A mediator is an object that oversees all actions among a group of similar components called colleagues. If the state of one colleague changes, it could mean that the state of another should also change as well. To keep dependencies from getting tangled up, a mediator object is used to pass all of the data between colleagues.

<div style="width:100%; margin:auto;text-align:center;"><img src="https://www.devmaking.com/img/topics/designpatterns/MediatorPattern_01.png" alt="mediator pattern UML diagram" style="max-width:95%;"> </div>

Mediators are very useful for GUI components such as buttons; clicking on one checkbox might mean another should show itself or disappear.

Conceptualization

Let's create an online dungeons and dragons game; our Dungeon master will be the mediator and our players will be the colleagues on their quest for greatness.

<div style="width:100%; margin:auto;text-align:center;"><img src="https://www.devmaking.com/img/topics/designpatterns/MediatorPattern_02.png" alt="dungeon master mediator UML diagram" style="max-width:95%;"> </div>

To start, we'll make our dungeon master interface and an abstract class for a player with some methods implemented:

interface IDungeonMaster {
   void sendMessage(Player fromPlayer, String message);
   void broadcastRoll(Player fromPlayer, int number);
   
 }

abstract class Player {
   
   IDungeonMaster dm;
   
   Player(IDungeonMaster dm) {
     this.dm = dm;
   }
   
   void talkToDM(String message) {
     dm.sendMessage(this, message);
   }
   void rollDice() {
     roll = Random.randInt(0,20);
     if(roll &gt; 15) {
       talkToDM("High roll!");
     }
     dm.broadcastRoll(this, roll);
   }
   
   abstract String getName();
 }

The Dungeon Master will be the reference point between all actions the players make, and has methods to facilitate this interaction. The sendMessage method broadcasts a player's message to the screen. If it's an online game, it could be broadcasting the message out to all the players in the game. The next method, broadcastRoll handles the logic for what happens on each roll after a player takes their turn.

Now that we have our core classes setup, let's add a few player types. We want to keep the game simple for example purposes, so we'll just override their getName method:

class Knight extends Player {
   
   Knight(IDungeonMaster dm) {
     super(dm);
   }
   
      String getName() {
     return "Great Sir Knight";
   }
 }

class Mage extends Player{
   
   Mage(IDungeonMaster dm) {
     super(dm);
   }
   
   String getName() {
     return "Mystic Mage";
   }
 }

Now that we have our unlikely duo of Sir Knight and Mage, we can implement our DungeonMaster mediator that will handle the messages sent from our adventuring colleagues:

class DungeonMaster implements IDungeonMaster {
   
   // When the DM gets a message, we'll print it out to the screen:
   void sendMessage(Player fromPlayer, String message) {
     print(fromPlayer.getName() + " says: \"" + message + "\"");      
   }
   
   // Broadcasts the roll to the screen:
   void broadCastRoll(Player fromPlayer, int number) {
     print(fromPlayer.getName() + " rolls " + number);
     // Handles what happens at different numbers:
     if(number &lt; 10) {
       print("Dungeon Master: You are ambushed by goblins!");
     }
     else if (number &lt; 15) {
       print("Dungeon Master: You safely continue the journey.");
     }
     else {
       print("Dungeon Master: You found some loot!");
     }
   }
 }

> A popular pattern to use with the Mediator is an <a href="https://www.devmaking.com/learn/design-patterns/observer-pattern/" target="_blank" style="color:inherit;">Observer Pattern</a>. In our case, using an observer could allow us to talk to each player individually and do thing's like affect the player's stats.

Finally, we can see how our game performs in a client code situation!

class DungeonsOnline {
   
   static void main(String[] args) {
     // Create our DM:
     IDungeonMaster dm = new DungeonMaster();
     // Some Players:
     Player p1 = new Knight();
     Player p2 = new Mage();
     
     // Have each player roll 3 times for 6 turns:
     for(int i = 0; i &lt; 3; i++) {
       p1.rollDice();
       p2.rollDice();
     }
     // Done!
   }
 }

Output:

Great Sir Knight rolls 12
Dungeon Master: You safely continue the journey.
Mystic Mage rolls 8
Dungeon Master: You are ambushed by goblins!
Great Sir Knight Rolls 20
Great Sir Knight says: "High Roll!"
Dungeon Master: You found some loot!
Mystic Mage rolls 12
Dungeon Master: You safely continue the journey.
Great Sir Knight Rolls 3
Dungeon Master: You are ambushed by goblins!
Mystic Mage rolls 18
Mystic Mage says: "High Roll!"
Dungeon Master: You found some loot!

It might not be the most comprehensive tale of adventure to date, but with some improvement it could be a tale to remember!