Ilkka Seppälä 04bf566dc1
task: Explanations and grammar fixes for all the GoF patterns (#1791)
* 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
2021-06-24 18:27:20 +05:30

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
![alt text](./etc/mediator_1.png "Mediator")
## 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)