In this article, we will learn how to use and implement the Mediator Pattern in C++ with an example.
A mediator pattern is a behavioral design pattern that lets you reduce chaotic dependencies between objects. The pattern restricts direct communications between the objects and forces them to collaborate only via a mediator object.
C++ Mediator Pattern Example
The below diagram shows the generic structure of the Mediator Pattern:
Let's refer to the above structure to create an example to demonstrates the usage of the Mediator Pattern.
#include <iostream> #include <vector> #include <string> class Mediator; /* * Colleague classes * each colleague communicates with its mediator whenever * it would have otherwise communicated with another colleague */ class Colleague { public: Colleague( Mediator* const m, const unsigned int i ) : mediator( m ), id( i ) {} virtual ~Colleague() {} unsigned int getID() { return id; } virtual void send( std::string ) = 0; virtual void receive( std::string ) = 0; protected: Mediator *mediator; unsigned int id; }; class ConcreteColleague : public Colleague { public: ConcreteColleague( Mediator* const m, const unsigned int i ) : Colleague( m, i ) {} ~ConcreteColleague() {} void send( std::string msg ); void receive( std::string msg ) { std::cout << "Message '" << msg << "' received by Colleague " << id << std::endl; } }; /* * Mediator * defines an interface for communicating with Colleague objects */ class Mediator { public: virtual ~Mediator() {} virtual void add( Colleague* const c ) = 0; virtual void distribute( Colleague* const sender, std::string msg ) = 0; protected: Mediator() {} }; /* * Concrete Mediator * implements cooperative behavior by coordinating Colleague objects * and knows its colleagues */ class ConcreteMediator : public Mediator { public: ~ConcreteMediator() { for ( unsigned int i = 0; i < colleagues.size(); i++ ) { delete colleagues[ i ]; } colleagues.clear(); } void add( Colleague* const c ) { colleagues.push_back( c ); } void distribute( Colleague* const sender, std::string msg ) { for ( unsigned int i = 0; i < colleagues.size(); i++ ) { if ( colleagues.at( i )->getID() != sender->getID() ) { colleagues.at( i )->receive( msg ); } } } private: std::vector<Colleague*> colleagues; }; void ConcreteColleague::send( std::string msg ) { std::cout << "Message '"<< msg << "' sent by Colleague " << id << std::endl; mediator->distribute( this, msg ); } int main() { Mediator *mediator = new ConcreteMediator(); Colleague *c1 = new ConcreteColleague( mediator, 1 ); Colleague *c2 = new ConcreteColleague( mediator, 2 ); Colleague *c3 = new ConcreteColleague( mediator, 3 ); mediator->add( c1 ); mediator->add( c2 ); mediator->add( c3 ); c1->send( "Hi!" ); c3->send( "Hello!" ); delete mediator; return 0; }
Output
Message 'Hi!' sent by Colleague 1
Message 'Hi!' received by Colleague 2
Message 'Hi!' received by Colleague 3
Message 'Hello!' sent by Colleague 3
Message 'Hello!' received by Colleague 1
Message 'Hello!' received by Colleague 2
When to Use Mediator Pattern
- Use the Mediator pattern when it’s hard to change some of the classes because they are tightly coupled to a bunch of other classes.
- Use the pattern when you can’t reuse a component in a different program because it’s too dependent on other components.
- Use the Mediator when you find yourself creating tons of component subclasses just to reuse some basic behavior in various contexts
Related C++ Design Patterns
- C++ Factory Method Pattern Example
- C++ Builder Pattern Example
- C++ Abstract Factory Pattern Example
- C++ Bridge Pattern Example
- C++ Chain of Responsibility Pattern Example
- C++ Composite Pattern Example
- C++ Decorator Pattern Example
- C++ Facade Pattern Example
- C++ Mediator Pattern Example
- C++ Memento Pattern Example
- C++ Observer Pattern Example
- C++ Proxy Pattern Example
- C++ Strategy Pattern Example
- C++ State Pattern Example
- C++ Visitor Pattern Example