- 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.
- Design an intermediary to decouple many peers.
- Promote the many-to-many relationships between interacting peers to “full object status”.
Problem
We want to design reusable components, but dependencies between the potentially reusable pieces demonstrate the “spaghetti code” phenomenon (trying to scoop single serving results in an “all or nothing clump”).
Here is our template Mediator class to register, unregister and send the message.
template <typename T>
class Mediator
{
typedef void (*Action)(T);
private:
std::multimap<std::string, std::list<Action> > actions;
public:
Mediator(void)
{
}
~Mediator(void)
{
}
void Register(std::string message, Action action)
{
std::multimap<std::string, std::list<Action> >::iterator iter_ = actions.find(message);
if (iter_ != actions.end())
{
iter_->second.push_back(action);
}
else
{
std::list<Action> list;
list.push_back(action);
actions.insert(std::pair<std::string, std::list<Action> >(message, list));
}
}
void UnRegister(std::string message, Action action)
{
std::multimap<std::string, std::list<Action> >::iterator iter_ = actions.find(message);
if (iter_ != actions.end())
{
iter_->second.remove(action);
}
}
void Send(std::string message, T param)
{
std::multimap<std::string, std::list<Action> >::iterator iter_ = actions.find(message);
if (iter_ != actions.end())
{
std::list<Action>::iterator listIter_ = iter_->second.begin();
while (listIter_ != iter_->second.end())
{
(*listIter_)(param);
listIter_++;
}
}
}
};
Now let’s make some client for this mediator. Here is our first client for this class. Rest of the client are very similar to this, therefore we show the code of only one client.
#pragma once
#include <string>
#include "Mediator.h"
class FirstClient
{
private:
Mediator<std::string> mediator;
public:
FirstClient(void);
FirstClient(Mediator<std::string> mediator);
~FirstClient(void);
static void Notify(std::string message);
void SendMessages();
};
And here is an implementation of this class.
#include "FirstClient.h"
#include <iostream>
FirstClient::FirstClient(void)
{
}
FirstClient::FirstClient(Mediator<std::string> mediator)
{
this->mediator = mediator;
}
FirstClient::~FirstClient(void)
{
}
void FirstClient::Notify(std::string message)
{
std::cout << "[FirstClient]"
<< '\t'
<< message
<< std::endl;
}
void FirstClient::SendMessages()
{
mediator.Send("1", "message 1 from FirstClient");
mediator.Send("2", "message 2 from FirstClient");
}
Rest of the client are very similar to this the only difference is they might send different type of messages.
We have to register the call back functions for each message in these classes. Here is our main to register these messages and their call back methods
Now if we simply call SendMessages method of each client then mediator automatically calls all the registered call back methods based on the message. Here is complete code of our main program.
#include "Mediator.h"
#include "FirstClient.h"
#include "SecondClient.h"
#include <string>
#include <iostream>
int main()
{
Mediator<std::string> med;
med.Register("1", FirstClient::Notify);
med.Register("1", SecondClient::Notify);
med.Register("2", SecondClient::Notify);
FirstClient fc(med);
SecondClient sc(med);
fc.SendMessages();
sc.SendMessages();
return 0;
}
There are two important points to notice in this program.
First our mediator class is independent of all of the classes. In other words we can use our mediator class in any project without changing it and without include any other header file.
Second all of our clients are dependent only on mediator and they don’t know anything about each other means they do not physically depend on other clients. If we want to use them in other project then the only dependency involved is Mediator class, which itself is very useful and independent of any other class.