Card 03/ 08
Mediator Template in Python, Java and TypeScript
Three colleagues that never reference each other, and one mediator that reacts to each.
The Mediator template is the pattern in its pure form, with the participant names from the class diagram. Three colleagues, A, B and C, each report a change to the mediator. The mediator's rules are that a change in A updates B and C, a change in B updates C, and a change in C updates nobody. The steps build the Python version, and the tabs give the complete program in three languages, each with its output.
Building the template one part at a time
Mediator
One method that every colleague calls.
@abstractmethod
def notify(self, sender: "Colleague", event: str) -> None: ...Colleague
Reports its own change, and never names another colleague.
def change(self, event: str) -> None:
print(f"{self.name}: {event}")
self.mediator.notify(self, event)Concrete mediator
Holds every rule about who reacts to whom.
def notify(self, sender: Colleague, event: str) -> None:
if sender is self.a:
self.b.react(f"A's {event}")
self.c.react(f"A's {event}")
elif sender is self.b:
self.c.react(f"B's {event}")The complete template
from abc import ABC, abstractmethod
class Mediator(ABC):
@abstractmethod
def notify(self, sender: "Colleague", event: str) -> None: ...
class Colleague:
def __init__(self, name: str, mediator: Mediator) -> None:
self.name = name
self.mediator = mediator
def change(self, event: str) -> None:
print(f"{self.name}: {event}")
self.mediator.notify(self, event)
def react(self, reason: str) -> None:
print(f" {self.name} reacts to {reason}")
class ConcreteMediator(Mediator):
def __init__(self) -> None:
self.a = Colleague("A", self)
self.b = Colleague("B", self)
self.c = Colleague("C", self)
def notify(self, sender: Colleague, event: str) -> None:
if sender is self.a:
self.b.react(f"A's {event}")
self.c.react(f"A's {event}")
elif sender is self.b:
self.c.react(f"B's {event}")
mediator = ConcreteMediator()
mediator.a.change("x")
mediator.b.change("y")
mediator.c.change("z")A: x
B reacts to A's x
C reacts to A's x
B: y
C reacts to B's y
C: zpublic class MdTemplate {
public static void main(String[] args) {
ConcreteMediator mediator = new ConcreteMediator();
mediator.a.change("x");
mediator.b.change("y");
mediator.c.change("z");
}
}
interface Mediator {
void notify(Colleague sender, String event);
}
class Colleague {
private final String name;
private final Mediator mediator;
Colleague(String name, Mediator mediator) {
this.name = name;
this.mediator = mediator;
}
void change(String event) {
System.out.println(name + ": " + event);
mediator.notify(this, event);
}
void react(String reason) {
System.out.println(" " + name + " reacts to " + reason);
}
}
class ConcreteMediator implements Mediator {
final Colleague a = new Colleague("A", this);
final Colleague b = new Colleague("B", this);
final Colleague c = new Colleague("C", this);
public void notify(Colleague sender, String event) {
if (sender == a) {
b.react("A's " + event);
c.react("A's " + event);
} else if (sender == b) {
c.react("B's " + event);
}
}
}A: x
B reacts to A's x
C reacts to A's x
B: y
C reacts to B's y
C: zinterface Mediator {
notify(sender: Colleague, event: string): void;
}
class Colleague {
constructor(readonly name: string, private readonly mediator: Mediator) {}
change(event: string): void {
console.log(`${this.name}: ${event}`);
this.mediator.notify(this, event);
}
react(reason: string): void {
console.log(` ${this.name} reacts to ${reason}`);
}
}
class ConcreteMediator implements Mediator {
readonly a = new Colleague("A", this);
readonly b = new Colleague("B", this);
readonly c = new Colleague("C", this);
notify(sender: Colleague, event: string): void {
if (sender === this.a) {
this.b.react(`A's ${event}`);
this.c.react(`A's ${event}`);
} else if (sender === this.b) {
this.c.react(`B's ${event}`);
}
}
}
const mediator = new ConcreteMediator();
mediator.a.change("x");
mediator.b.change("y");
mediator.c.change("z");A: x
B reacts to A's x
C reacts to A's x
B: y
C reacts to B's y
C: zA's change reaches B and C, B's reaches C, and C's reaches nobody, as the rules say. Colleague has no field that refers to another colleague, so all three are the same class here and could be used with any mediator.
Every rule about the interaction is in ConcreteMediator.notify. Changing the rules, such as making C's change update A, is an edit to that one method, and no colleague changes. The pattern makes a trade: the colleagues become simple, and the mediator holds what they no longer do.
← → move through sections and cards