* Grammatical fixes to command pattern * Update bridge pattern readme * Fixes to builder pattern grammar * Update chain of responsibility * Improvements to the composite example * Fixes to headings * Minor updates to decorator pattern * Update facade * Update factory example * Update factory method * Update flyweight * Interpreter explanation * Update iterator readme * Add explanation for mediator pattern * Grammatical fixes to memento * Grammar fixes for observer * Update explanation for the prototype pattern * Proxy pattern grammar fixes * Update singleton * Grammar fixes to state pattern * Grammar fixes for strategy * Grammar fixes, template method * Grammar fixes for visitor * Fix typo
211 lines
6.4 KiB
Markdown
211 lines
6.4 KiB
Markdown
---
|
|
layout: pattern
|
|
title: Mediator
|
|
folder: mediator
|
|
permalink: /patterns/mediator/
|
|
categories: Behavioral
|
|
language: en
|
|
tags:
|
|
- Gang Of Four
|
|
- Decoupling
|
|
---
|
|
|
|
## Intent
|
|
|
|
Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling
|
|
by keeping objects from referring to each other explicitly, and it lets you vary their interaction
|
|
independently.
|
|
|
|
## Explanation
|
|
|
|
Real-world example
|
|
|
|
> Rogue, wizard, hobbit, and hunter have decided to join their forces and travel in the same
|
|
> party. To avoid coupling each member with each other, they use the party interface to
|
|
> communicate with each other.
|
|
|
|
In plain words
|
|
|
|
> Mediator decouples a set of classes by forcing their communications flow through a mediating
|
|
> object.
|
|
|
|
Wikipedia says
|
|
|
|
> In software engineering, the mediator pattern defines an object that encapsulates how a set of
|
|
> objects interact. This pattern is considered to be a behavioral pattern due to the way it can
|
|
> alter the program's running behavior. In object-oriented programming, programs often consist of
|
|
> many classes. Business logic and computation are distributed among these classes. However, as
|
|
> more classes are added to a program, especially during maintenance and/or refactoring, the
|
|
> problem of communication between these classes may become more complex. This makes the program
|
|
> harder to read and maintain. Furthermore, it can become difficult to change the program, since
|
|
> any change may affect code in several other classes. With the mediator pattern, communication
|
|
> between objects is encapsulated within a mediator object. Objects no longer communicate directly
|
|
> with each other, but instead communicate through the mediator. This reduces the dependencies
|
|
> between communicating objects, thereby reducing coupling.
|
|
|
|
**Programmatic Example**
|
|
|
|
In this example, the mediator encapsulates how a set of objects interact. Instead of referring to
|
|
each other directly they use the mediator interface.
|
|
|
|
The party members `Rogue`, `Wizard`, `Hobbit`, and `Hunter` all inherit from the `PartyMemberBase`
|
|
implementing the `PartyMember` interface.
|
|
|
|
```java
|
|
public interface PartyMember {
|
|
|
|
void joinedParty(Party party);
|
|
|
|
void partyAction(Action action);
|
|
|
|
void act(Action action);
|
|
}
|
|
|
|
@Slf4j
|
|
public abstract class PartyMemberBase implements PartyMember {
|
|
|
|
protected Party party;
|
|
|
|
@Override
|
|
public void joinedParty(Party party) {
|
|
LOGGER.info("{} joins the party", this);
|
|
this.party = party;
|
|
}
|
|
|
|
@Override
|
|
public void partyAction(Action action) {
|
|
LOGGER.info("{} {}", this, action.getDescription());
|
|
}
|
|
|
|
@Override
|
|
public void act(Action action) {
|
|
if (party != null) {
|
|
LOGGER.info("{} {}", this, action);
|
|
party.act(this, action);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public abstract String toString();
|
|
}
|
|
|
|
public class Rogue extends PartyMemberBase {
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "Rogue";
|
|
}
|
|
}
|
|
|
|
// Wizard, Hobbit, and Hunter are implemented similarly
|
|
```
|
|
|
|
Our mediator system consists of `Party` interface and its implementation.
|
|
|
|
```java
|
|
public interface Party {
|
|
|
|
void addMember(PartyMember member);
|
|
|
|
void act(PartyMember actor, Action action);
|
|
}
|
|
|
|
public class PartyImpl implements Party {
|
|
|
|
private final List<PartyMember> members;
|
|
|
|
public PartyImpl() {
|
|
members = new ArrayList<>();
|
|
}
|
|
|
|
@Override
|
|
public void act(PartyMember actor, Action action) {
|
|
for (var member : members) {
|
|
if (!member.equals(actor)) {
|
|
member.partyAction(action);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void addMember(PartyMember member) {
|
|
members.add(member);
|
|
member.joinedParty(this);
|
|
}
|
|
}
|
|
```
|
|
|
|
Here's a demo showing the mediator pattern in action.
|
|
|
|
```java
|
|
// create party and members
|
|
Party party = new PartyImpl();
|
|
var hobbit = new Hobbit();
|
|
var wizard = new Wizard();
|
|
var rogue = new Rogue();
|
|
var hunter = new Hunter();
|
|
|
|
// add party members
|
|
party.addMember(hobbit);
|
|
party.addMember(wizard);
|
|
party.addMember(rogue);
|
|
party.addMember(hunter);
|
|
|
|
// perform actions -> the other party members
|
|
// are notified by the party
|
|
hobbit.act(Action.ENEMY);
|
|
wizard.act(Action.TALE);
|
|
rogue.act(Action.GOLD);
|
|
hunter.act(Action.HUNT);
|
|
```
|
|
|
|
Here's the console output from running the example.
|
|
|
|
```
|
|
Hobbit joins the party
|
|
Wizard joins the party
|
|
Rogue joins the party
|
|
Hunter joins the party
|
|
Hobbit spotted enemies
|
|
Wizard runs for cover
|
|
Rogue runs for cover
|
|
Hunter runs for cover
|
|
Wizard tells a tale
|
|
Hobbit comes to listen
|
|
Rogue comes to listen
|
|
Hunter comes to listen
|
|
Rogue found gold
|
|
Hobbit takes his share of the gold
|
|
Wizard takes his share of the gold
|
|
Hunter takes his share of the gold
|
|
Hunter hunted a rabbit
|
|
Hobbit arrives for dinner
|
|
Wizard arrives for dinner
|
|
Rogue arrives for dinner
|
|
```
|
|
|
|
## Class diagram
|
|
|
|

|
|
|
|
## Applicability
|
|
|
|
Use the Mediator pattern when
|
|
|
|
* A set of objects communicate in well-defined but complex ways. The resulting interdependencies are unstructured and difficult to understand
|
|
* Reusing an object is difficult because it refers to and communicates with many other objects
|
|
* A behavior that's distributed between several classes should be customizable without a lot of subclassing
|
|
|
|
## Known uses
|
|
|
|
* All scheduleXXX() methods of [java.util.Timer](http://docs.oracle.com/javase/8/docs/api/java/util/Timer.html)
|
|
* [java.util.concurrent.Executor#execute()](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable-)
|
|
* submit() and invokeXXX() methods of [java.util.concurrent.ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)
|
|
* scheduleXXX() methods of [java.util.concurrent.ScheduledExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html)
|
|
* [java.lang.reflect.Method#invoke()](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html#invoke-java.lang.Object-java.lang.Object...-)
|
|
|
|
## Credits
|
|
|
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
|
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|