Mediator pattern defines an object (mediator) that encapsulates how a set of objects interact. It promotes loose coupling by preventing objects from referring to each other explicitly, allowing their interaction to be managed in one central place - the mediator. Instead of communicating directly, objects (colleagues) send messages to a mediator, which handles the routing of communication. This reduces the complexity and dependencies between objects.
Applicability
- When objects communicate in a complex, tightly-coupled way that’s hard to manage and maintain
- When you want to centralise control logic and reduce dependencies between communicating components
- Especially useful in GUI systems, chat applications, air traffic control systems, or form handling, where multiple objects need to coordinate.
Pros and Cons
Advantages
- Reduces coupling between components
- Components (colleagues) do not need to know about each other; they only communicate with the mediator.
- Centralised control logic
- All communication logic is in one place, making it easier to manage, maintain, and extend.
- Easier to modify and reuse components
- Since components don’t depend on each other directly, they can be reused and replaced independently.
Drawbacks
- Mediator can become a complex god object
- If not designed carefully, the mediator can grow large and hard to manage, especially when it handles many interactions.
- Overhead for simple communications
- Introducing a mediator may be overkill if the interactions are minimal or simple.
Approach
- Define the Mediator interface that declares communication methods
- Define the Colleague abstract class or interface for components that will communicate via the mediator
- Implement concrete colleagues that use the mediator instead of communicating directly
- Implement the concrete mediator, handling the interactions and business logic between colleague objects
Components
- Mediator (abstract/interface)
- Declares methods to facilitate communication between colleague objects.
- ConcreteMediator
- Implements the coordination logic between colleague objects.
- Colleague (abstract/interface)
- A base component that holds a reference to the mediator and communicates through it.
- ConcreteColleague
- Implements component-specific behaviour and sends/receives messages via the mediator.
Example (Python)
# Concrete mediator
class SmartHomeMediator:
def __init__(self):
self.devices = {}
def register_device(self, device_name, device):
self.devices[device_name] = device
device.mediator = self
def notify(self, sender, event):
if event == "motion_detected":
# Turn on lights when motion is detected
if "light" in self.devices:
self.devices["light"].turn_on()
elif event == "temperature_high":
# Turn on AC when temperature is too high
if "ac" in self.devices:
self.devices["ac"].turn_on()
elif event == "leaving_home":
# Turn off all devices when leaving home
for device in self.devices.values():
if device != sender:
device.turn_off()
# Colleague
class SmartDevice:
def __init__(self, name):
self.name = name
self.mediator = None
self.is_on = False
def turn_on(self):
self.is_on = True
print(f"{self.name} turned ON")
def turn_off(self):
self.is_on = False
print(f"{self.name} turned OFF")
# Concrete collegue
class MotionSensor(SmartDevice):
def detect_motion(self):
print("Motion detected!")
self.mediator.notify(self, "motion_detected")
class ThermostatSensor(SmartDevice):
def set_temperature(self, temp):
print(f"Temperature set to {temp}")
if temp > 25: # Celsius
self.mediator.notify(self, "temperature_high")
class RemoteControl(SmartDevice):
def leaving_home_button(self):
print("Leaving home button pressed")
self.mediator.notify(self, "leaving_home")
# Client
home = SmartHomeMediator()
light = SmartDevice("Living Room Light")
ac = SmartDevice("Air Conditioner")
motion_sensor = MotionSensor("Hallway Sensor")
thermostat = ThermostatSensor("Main Thermostat")
remote = RemoteControl("Remote Control")
home.register_device("light", light)
home.register_device("ac", ac)
home.register_device("motion_sensor", motion_sensor)
home.register_device("thermostat", thermostat)
home.register_device("remote", remote)
# Test scenarios
motion_sensor.detect_motion() # Should turn on lights
thermostat.set_temperature(28) # Should turn on AC
remote.leaving_home_button() # Should turn everything off
Back to parent page: Behavioural Patterns
Design_Pattern Behavioural_Design_Patterns Mediator_Pattern SOFT3202