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!

No comments:

Post a Comment