Posted by: Zeeshan Amjad | April 25, 2012

Mediator Design pattern using C++


We already saw a series of example to implement Mediator design pattern in C# here. We can do the same thing with the help of STL, function pointer and template in C++ in unmanaged code. But in case of C++, we are getting one more advantage as a bonus and that is reduce the compilation dependencies among different component of the program. First let’s take a look at C++ version of our mediator pattern. Here is our template Mediator class to register, unregister and send the message. In this program we are using multimap instead of dictionary.

Code Snippet
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.

Code Snippet
#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.

Code Snippet
#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 messages in these classes. Here is our main to register these messages and their call back methods.

Code Snippet
Mediator<std::string> med;

med.Register("1", FirstClient::Notify);
med.Register("1", SecondClient::Notify);
med.Register("1", ThirdClient::Notify);
med.Register("1", FourthClient::Notify);
med.Register("2", ThirdClient::Notify);
med.Register("2", FourthClient::Notify);
med.Register("3", SecondClient::Notify);

 

Now if we simply call SendMessage method of each client then mediator will automatically calls all the registered call back methods based on the message. Here is complete code of our main program.

Code Snippet
// Main.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Mediator.h"
#include "FirstClient.h"
#include "SecondClient.h"
#include "ThirdClient.h"
#include "FourthClient.h"

#include <string>
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
    Mediator<std::string> med;

    med.Register("1", FirstClient::Notify);
    med.Register("1", SecondClient::Notify);
    med.Register("1", ThirdClient::Notify);
    med.Register("1", FourthClient::Notify);
    med.Register("2", ThirdClient::Notify);
    med.Register("2", FourthClient::Notify);
    med.Register("3", SecondClient::Notify);

    FirstClient fc(med);
    SecondClient sc(med);
    ThirdClient tc(med);
    FourthClient foc(med);

    fc.SendMessages();
    sc.SendMessages();
    tc.SendMessages();
    foc.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 client is dependent only on mediator and they don’t know anything about each other means they are not physical depends 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.

We can represent this with the following diagram.

Mediator

This diagram clearly shows that all of our clients only depends on mediator and our main program depends not only on mediator but all four clients.

However in case of absence of mediator every client is going to communicate with other client directly and therefore create physical dependencies. This diagram shows the worst case situation when every client has to communicate with every other client without mediator.

NonMediator

 

These two diagram clearly shows that using mediator not only improve the logical design of our program, but also improve the physical design of our program too.

Advertisements

Responses

  1. Hi,

    great set of articles, I wonder whether the blog template can be modified so more space can be allocated to the content div; it only uses 525px which is far too small for the actual monitor sizes and truncates source code and images.

    • Hi EAG

      Thanks for such a good advice. I am not an expert of WordPress, but i will take a look at this and see if I can do it or have to change the theme altogether. Thanks to like my blog and visit here.

      Regards
      Zeeshan Amjad


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: