Skip to main content

The Mediator Pattern

Mediator pattern is used to loosely couple object interaction. If objects are tightly coupled, resuability disappears and maintenance becomes harder. A real life scenario will explain the pattern the best. Think about an airport control tower. It's task is to moderate the flight landings. If many aircrafts arrive simultaneously, only one can land at a time and the rest have to stay out from landing until signaled by the tower. This behavior exactly matches that of the mediator pattern. The aircrafts don't communicate with each other but yet they communicate through the control tower so that they can avoid disaster. The C++ code simulating the landing of planes, helicopters and private jets at an airport is simulated in this code. Assume only one airstrip.

#include "AirCraft.h"
#include "Mediator.h"
AirCraft::AirCraft(Mediator* med) {
med_ = med;
}
AirCraft::AirCraft(const AirCraft& orig) {
}
AirCraft::~AirCraft() {
}
void AirCraft::Land() {
med_->Land(this);
}
view raw AirCraft.cpp hosted with ❤ by GitHub
#ifndef AIRCRAFT_H
#define AIRCRAFT_H
#include <iostream>
using namespace std;
class Mediator;
class AirCraft {
public:
AirCraft(Mediator* med);
AirCraft(const AirCraft& orig);
virtual ~AirCraft();
virtual void Landing() = 0;
virtual void StayOut() = 0;
virtual void Land();
void SetID(int id_) {
id = id_;
}
int GetID() {
return id;
}
private:
int id;
Mediator* med_;
};
class Plane : public AirCraft {
public:
Plane(int id_, Mediator* med) : AirCraft(med) {
SetID(id_);
}
virtual ~Plane() {
}
void Landing() {
std::cout << "Plane Landing " << GetID() << std::endl;
}
void StayOut() {
std::cout << "Plane Out of the way... " << GetID() << std::endl;
}
};
class Heli : public AirCraft {
public:
Heli(int id_, Mediator* med) : AirCraft(med) {
SetID(id_);
}
virtual ~Heli() {
}
void Landing() {
std::cout << "Heli Landing " << GetID() << std::endl;
}
void StayOut() {
std::cout << "Heli Out of the way... " << GetID() << std::endl;
}
};
class Jet : public AirCraft {
public:
Jet(int id_, Mediator* med) : AirCraft(med) {
SetID(id_);
}
virtual ~Jet() {
}
void Landing() {
std::cout << "Jet Landing " << GetID() << std::endl;
}
void StayOut() {
std::cout << "Jet Out of the way... " << GetID() << std::endl;
}
};
#endif /* AIRCRAFT_H */
view raw AirCraft.h hosted with ❤ by GitHub
#include "AirCraft.h"
#include "Mediator.h"
int main(int argc, char** argv) {
Mediator *med = new Mediator();
Plane *p = new Plane(1, med);
Heli *h = new Heli(2, med);
Jet *j = new Jet(3, med);
Jet *j1 = new Jet(4, med);
med->RegisterAirCraft(p);
med->RegisterAirCraft(h);
med->RegisterAirCraft(j);
med->RegisterAirCraft(j1);
p->Land();
j->Land();
j1->Land();
h->Land();
return 0;
}
view raw main.cpp hosted with ❤ by GitHub
#include "Mediator.h"
Mediator::Mediator() {
}
Mediator::Mediator(const Mediator& orig) {
}
Mediator::~Mediator() {
}
void Mediator::Land(AirCraft *craft) {
cout << "Mediator Will Take Over Landing" << endl;
list<AirCraft*>::iterator it;
for (it = list_ac.begin(); it != list_ac.end(); it++) {
if (*it == craft) {
(*it)->Landing();
} else {
(*it)->StayOut();
}
}
for (it = list_ac.begin(); it != list_ac.end(); it++) {
if (*it == craft) {
list_ac.erase(it);
break;
}
}
}
view raw Mediator.cpp hosted with ❤ by GitHub
#ifndef MEDIATOR_H
#define MEDIATOR_H
#include <list>
#include <iostream>
#include "AirCraft.h"
using namespace std;
class Mediator {
public:
Mediator();
Mediator(const Mediator& orig);
virtual ~Mediator();
void RegisterAirCraft(AirCraft *craft) {
list_ac.push_back(craft);
}
void Land(AirCraft *craft);
private:
list <AirCraft*> list_ac;
};
#endif /* MEDIATOR_H */
view raw Mediator.h hosted with ❤ by GitHub

The output:

Mediator Will Take Over Landing
Plane Landing 1
Heli Out of the way... 2
Jet Out of the way... 3
Jet Out of the way... 4
Mediator Will Take Over Landing
Heli Out of the way... 2
Jet Landing 3
Jet Out of the way... 4
Mediator Will Take Over Landing
Heli Out of the way... 2
Jet Landing 4
Mediator Will Take Over Landing
Heli Landing 2

Comments

Popular posts from this blog

Detaching a process from terminal - exec(), system(), setsid() and nohup

Linux processes are created by fork() and exec(). The very first process of POSIX systems is init and subsequent processes are derived from the init as parent. These subsequent processes are child processes. During forking the parent process copies itself - with all I/O, address space, stack, everything. The only thing that is different is the process ID. The parent and child will have 2 different process IDs. The system() library function uses fork(2) to create a child process that executes the shell command specified in command using execl(3) as follows: execl("/bin/sh", "sh", "-c", command, (char *) 0); system() returns after the command has been completed. system() executes a command specified in command by calling /bin/sh -c command , and returns after the command has been completed. During execution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored.  system() calls are often made within programs to execut...

C++ Callbacks using function pointers vs boost bind +boost function

In C, the most common uses of callbacks are as parameters to library functions like qsort , and as callbacks for Windows functions, etc. For example you might have a library that provides some sorting functions but you want to allow the library user to provide his own sorting function. Since the arguments and the return values do not change depending on the sorting algorithm, this can be facilitated in a convenient manner using function callbacks. Callbacks are also used as event listeners. onMouseClick(), onTerminalInput(), onData(), onConnectionStatus(), onRead() are probably some examples you've already seen in different libraries. The libraries have these callback functions and the users of the library are supposed to implement them. The library has a function pointer to these functions and calls them on their event loop which will invoke the code of the inherited classes of the library user. The implementation of function pointers is simple: they are just "code p...

sprintf, snprintf, strcpy, strncpy and sizeof operator

"C library functions such as strcpy (), strcat (), sprintf () and vsprintf () operate on null terminated strings and perform no bounds checking." "snprintf is safer than sprintf" What do these statements really mean? int sprintf ( char * str , const char * format , ... )  int snprintf ( char * s, size_t n, const char * format, ... );  char * strcpy ( char * destination, const char * source ); char * strncpy ( char * destination, const char * source, size_t num );   The usage is something like; char* msg1 = new char[10]; strcpy(msg1, "test"); // 1 char buffer[128]; sprintf(buffer, "%s", msg); //2 strcpy : Copies bytes until it finds a 0-byte in the source code. The string literal "test" has 4 characters and a terminating null character at end, therefore needs 5 characters at least on msg1.  Is this dangerous? Yes, because if the source message is not null terminated it will read until a null character ...