- It 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.
- It defines an object that provides central authority over a group of objects by encapsulating how these objects interact.
- This model is useful for scenarios where there is a need to manage complex conditions in which every object is aware of every state change of other objects in the group.
- Mediator patterns are frequently used in the development of complex dialog boxes.
- Take for example a dialog in which you enter options to make a flight reservation.
- A simple Mediator rule would be: you must enter a valid departure date, a valid return date, the return date must be after the departure date, a valid departure airport, a valid arrival airport, a valid number of travelers, and only then the Search command button can be activated.
Participants
Mediator
(IMediator)
- Defines an interface for communicating with
Colleague
objects.
ConcreteMediator
(Mediator)
- Implements cooperative behavior by coordinating
Colleague
objects.
- Knows and maintains its
colleagues
.
Colleague
(IParticipant)
- Individual components that need to communicate with each other.
- It has the knowledge of the
Mediator
component.
- It communicates with its
Mediator
to communicated with another colleague
.
var messageMediator = new Mediator();
var participant1 = new PublicParticipant();
var participant2 = new PublicParticipant();
var participant3 = new PrivateParticipant();
var participant4 = new PrivateParticipant();
messageMediator.AddParticipant(participant1);
messageMediator.AddParticipant(participant2);
messageMediator.AddParticipant(participant3);
messageMediator.AddParticipant(participant4);
participant1.BroadcastMessage("Hi All!");
participant2.BroadcastMessage("All you need is love!");
participant3.BroadcastMessage("Can't buy me love...");
participant4.BroadcastMessage("My sweet love.");
public interface IParticipant
{
IMediator Mediator { get; set; }
void BroadcastMessage(string message);
}
public class PublicParticipant : IParticipant
{
public IMediator Mediator { get; set; }
public void BroadcastMessage(string message) => Mediator.BroadcastMessage($"Public participant: {message}");
}
public class PrivateParticipant : IParticipant
{
public IMediator Mediator { get; set; }
public void BroadcastMessage(string message) => Mediator.BroadcastMessage(message);
}
public interface IMediator
{
void AddParticipant(IParticipant participant);
void BroadcastMessage(string message);
}
public class Mediator : IMediator
{
private List<IParticipant> _participants = new List<IParticipant>();
public void AddParticipant(IParticipant participant)
{
if (!_participants.Contains(participant))
_participants.Add(participant);
participant.Mediator = this;
}
public void BroadcastMessage(string message) => _participants.ForEach(participant => participant.BroadcastMessage(message));
}
Rules of Thumb
- Chain of Responsibility, Command, Mediator, and Observer, address how you can decouple senders and receivers, but with different trade-offs.
- Chain of Responsibility passes a sender request along a chain of potential receivers.
- Command normally specifies a sender-receiver connection with a subclass.
- Mediator has senders and receivers reference each other indirectly.
- Observer defines a very decoupled interface that allows for multiple receivers to be configured at run-time.
- Mediator and Observer are competing patterns.
- The difference between them is that Observer distributes communication by introducing "observer" and "subject" objects
- Mediator object encapsulates the communication between other objects.
- It it easier to make reusable Observers and Subjects than to make reusable Mediators.
- On the other hand, Mediator can leverage Observer for dynamically registering colleagues and communicating with them.
- Mediator is similar to Facade in that it abstracts functionality of existing classes.
- Mediator abstracts/centralizes arbitrary communication between colleague objects, it routinely "adds value", and it is known/referenced by the colleague objects (i.e. it defines a multidirectional protocol).
- In contrast, Facade defines a simpler interface to a subsystem, it doesn't add new functionality, and it is not known by the subsystem classes (i.e. it defines a unidirectional protocol where it makes requests of the subsystem classes but not vice versa).