Showing posts with label Mediator Pattern. Show all posts
Showing posts with label Mediator Pattern. Show all posts

Saturday, May 24, 2014

Mediator in C++

New class, new project, same old people and they just can't get enough of my crazy singleton mediator goodness.  Now in exciting new C++ flavors!!

class Mediator
{
private:
 Mediator() {/*Filler!!*/}
 
 Mediator(const Mediator&) {/*Filler!!*/ }
 
 Mediator& operator = (const Mediator&) {/*Filler!!*/ }
 
 ~Mediator() {/*Filler!!*/ }
 
 static Mediator& Instance()
 {
  static Mediator instance;
  return instance;
 }
 
 std::map<std::string, std::vector<void (*)(void*)>> MediatorMap;
public:
 
 static void Register(std::string Key, void (*Function)(void*))
 {
  Instance().MediatorMap[Key].push_back(Function);
 }
 
 static void Unregister(std::string Key, void(*Function)(void*))
 {
  if (Instance().MediatorMap.count(Key) != 0)
  {
   Instance().MediatorMap[Key].erase(std::find(Instance().MediatorMap[Key].begin(),
         Instance().MediatorMap[Key].end(),
         Function));
  }
  if (Instance().MediatorMap[Key].size() == 0)
  {
   Instance().MediatorMap.erase(Instance().MediatorMap.find(Key));
  }
 }
 
 static void Call (std::string Key, void* Object = nullptr)
 {
  if (Instance().MediatorMap.count(Key) != 0)
  {
   for (std::vector<void(*)(void*)>::iterator It = Instance().MediatorMap[Key].begin();
        It != Instance().MediatorMap[Key].end();
               ++It)
   {
    (*It)(Object);
   }
  }
 }
 
 static void Clear()
 {
 Instance().MediatorMap.clear();
 }  
};

I started writing it as a template but the mixture of template and singleton were to much for my currently sick and heavily medicated self to figure out.  So, for now, instead of being able to use whatever kind of key you want you're currently stuck with using a string.

You might also be wondering why there are 230920934 Instance() calls.  Mostly so you can do the following:

Mediator::Register("Test", &TestFunction);
Mediator::Call("Test", "SPOOOON!!");
Mediator::Unregister("Test", &TestFunction);

For those of you new to singletons, normally you would have to do:

Mediator::Instance.Register("Test", &TestFunction);

But I don't like having to include the Instance method in the complete call.  Having all my methods static and referencing class variables through Instance() allows me to forgo that.  It's ugly, and there are probably better way to go about it but it is what it is.


[Edit/Update]

Changed the code just a little bit.  Changed the second parameter of our Call method to:

static void Call (std::string Key, void* Object = nullptr)

 This allows us to not have to send anything if our registered functions do not require an input.

Also added the Clear method.  This will completely empty our MediatorMap in the event this is ever required.  When will that be?  I don't know, but it's there if we need it.

As usual I am open to suggestions, comments, etc.  Thanks!

Monday, May 19, 2014

Mediator Pattern/Class

 This is my Mediator class.  Right now I'm using it like a singleton but it can be changed back to a normal class easily.  The template "T" allows you to use whatever kind of key you like.  You can use any number of keys and have any number of Actions (functions/methods) registered under them.  Using the Call method allows you to execute all functions/methods under the given Key and pass to them (the functions/methods) any object you desire.

public class Mediator<T>
 {
     private static Mediator<T> _Instance = new Mediator<T>();
 
     private Dictionary<T, List<Action<object>>> 
         _Callbacks = new Dictionary<T, List<Action<object>>>();
 
     private Mediator() { }
 
     public static Mediator<T> Instance
     {
         get
         {
             return _Instance;
         }
     }
 
     public static void Register(T Key, Action<object> Action)
     {
         if (!Instance._Callbacks.ContainsKey(Key))
         {
             Instance._Callbacks[Key] = new List<Action<object>>();
         }
 
         Instance._Callbacks[Key].Add(Action);
     }
 
     public static void Unregister(T Key, Action<object> Action)
     {
         Instance._Callbacks[Key].Remove(Action);
 
         if (Instance._Callbacks[Key].Count == 0)
         {
             Instance._Callbacks.Remove(Key);
         }
     }
 
     public static void Call(T Key, object Message = null)
     {
         if (Instance._Callbacks.ContainsKey(Key))
         {
             Instance._Callbacks[Key].ForEach(Action => Action(Message));
         }
     }
 }


A couple side notes:

First, not having code specific formatting is making my ass twitch.  I need to find a way to remedy that to make the code easier to read.  At least it's keeping the tabbing, right?

Second, since this is my first code post I would like to make it clear that I am open to any and all suggestions in regards to improving my code.  Constructive criticism, while sometimes hard to swallow, is almost always welcome.

[Edit]

So the solutions to the code specific formatting appears to be installing Productivity Power Tools for MSVS 20## (whatever version you're using.)  This is done and now you can see my code in all its colorful glory!