Mediator#

The Mediator pattern is a behavioral design pattern that lets you reduce chaotic dependencies between objects. The pattern restricts direct communications between the objects and forces them to collaborate only via a mediator object.

Key Points#

  1. Reducing Complexity: The Mediator pattern is used to reduce the complexity of communication between multiple objects or classes. The pattern provides a mediator that handles all the communications between different classes.

  2. Promoting Loose Coupling: The pattern promotes loose coupling by ensuring that instead of components referring to each other explicitly, their interaction is abstracted into this mediator.

  3. Reusing Objects: The pattern allows you to reuse individual components more easily because they no longer depend on a large number of other components.

  4. Centralizing Control: The pattern centralizes control. The mediator becomes the hub of communication, making it easier to understand the way objects interact and the potential paths of change.

Python Example#

from abc import ABC, abstractmethod

class Mediator(ABC):
    @abstractmethod
    def notify(self, sender: object, event: str) -> None:
        pass

class ConcreteMediator(Mediator):
    def __init__(self, component1: 'Component1', component2: 'Component2') -> None:
        self._component1 = component1
        self._component1.mediator = self
        self._component2 = component2
        self._component2.mediator = self

    def notify(self, sender: object, event: str) -> None:
        if event == "A":
            print("Mediator reacts on A and triggers following operations:")
            self._component2.do_c()
        elif event == "D":
            print("Mediator reacts on D and triggers following operations:")
            self._component1.do_b()
            self._component2.do_c()

class BaseComponent:
    def __init__(self, mediator: Mediator = None) -> None:
        self._mediator = mediator

    @property
    def mediator(self) -> Mediator:
        return self._mediator

    @mediator.setter
    def mediator(self, mediator: Mediator) -> None:
        self._mediator = mediator

class Component1(BaseComponent):
    def do_a(self) -> None:
        print("Component 1 does A.")
        self.mediator.notify(self, "A")

    def do_b(self) -> None:
        print("Component 1 does B.")
        self.mediator.notify(self, "B")

class Component2(BaseComponent):
    def do_c(self) -> None:
        print("Component 2 does C.")
        self.mediator.notify(self, "C")

    def do_d(self) -> None:
        print("Component 2 does D.")
        self.mediator.notify(self, "D")

Java Example#

public interface Mediator {
    void notify(Component sender, String event);
}

public class ConcreteMediator implements Mediator {
    private Component1 component1;
    private Component2 component2;

    public ConcreteMediator(Component1 component1, Component2 component2) {
        this.component1 = component1;
        this.component1.setMediator(this);
        this.component2 = component2;
        this.component2.setMediator(this);
    }

    @Override
    public void notify(Component sender, String event) {
        if (event.equals("A")) {
            System.out.println("Mediator reacts on A and triggers following operations:");
            this.component2.doC();
        } else if (event.equals("D")) {
            System.out.println("Mediator reacts on D and triggers following operations:");
            this.component1.doB();
            this.component2.doC();
        }
    }
}

public abstract class BaseComponent {
    protected Mediator mediator;

    public BaseComponent(Mediator mediator) {
        this.mediator = mediator;
    }

    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }
}

public class Component1 extends BaseComponent {
    public Component1(Mediator mediator) {
        super(mediator);
    }

    public void doA() {
        System.out.println("Component 1 does A.");
        mediator.notify(this, "A");
    }

    public void doB() {
        System.out.println("Component 1 does B.");
        mediator.notify(this, "B");
    }
}

public class Component2 extends BaseComponent {
    public Component2(Mediator mediator) {
        super(mediator);
    }

    public void doC() {
        System.out.println("Component 2 does C.");
        mediator.notify(this, "C");
    }

    public void doD() {
        System.out.println("Component 2 does D.");
        mediator.notify(this, "D");
    }
}

In these examples, ConcreteMediator knows and maintains relations between Component1 and Component2. Components only know about the Mediator interface and use it for communicating with other components. When a component changes its state, it notifies the mediator. Upon receiving the notification, the mediator may affect other components.