Я пытаюсь построить общую систему событий. Делегаты и мероприятия не должны знать что-либо о другом, и менеджер будет все делать.
Имея это в виду, я создал шаблонный делегат / слушатель, состоящий из указателя функции и шаблонных параметров.
class IDelegate
{
public:
IDelegate() {};
virtual ~IDelegate() = 0;
virtual void exec() = 0;
};
template<class Class, typename... Args>
class Delegate : public IDelegate
{
public:
typedef (Class::*Function)(Args);
Delegate(Class* inst, Function func) : instance(inst), function(func) {};
~Delegate() { instance = nullptr };
void exec(Args args)
{
instance->function(args);
}
private:
Class* instance;
Function function;
};
Я сделал что-то похожее на Событии. События, состоящие из идентификатора и аргументов, которые необходимо будет передать указателю на функцию.
class IEvent
{
public:
IEvent() {};
virtual ~IEvent() = 0;
};
template<typename... Args>
class Event : IEvent
{
public:
Event(ID eventID, Args args) : id(eventID), arguments(args) {};
~Event() = default;
ID id;
Args arguments;
};
Я предпочитаю использовать шаблоны в надежде на то, что не нужно вручную создавать каждый класс событий / делегатов, который может понадобиться.
Наконец, я хотел создать менеджера, который бы был синглтоном.
//EventHandler.h
#pragma once
#include <string>
#include <unordered_map>
#include <queue>
#include "Event.h"
typedef std::string ID;
typedef std::unordered_multimap<ID, void*> Listeners;
class EventHandler
{
public:
EventHandler(const EventHandler& copy) = delete;
~EventHandler();
EventHandler& operator= (const EventHandler& rhs) = delete;
void Initialize();
template<class Class, class TEvent>
void Run();
void Shutdown();
static Listeners::iterator& Register(ID id, IDelegate* listener);
static void Deregister(Listeners::iterator& iterator);
static void Post(IEvent* evnt);
private:
static Listeners listeners;
static std::queue<IEvent*> events;
static EventHandler* instance;
EventHandler() {};
EventHandler(const EventHandler& copy);
EventHandler& operator= (const EventHandler& rhs);
};
//EventHandler.cpp
#include "EventHandler.h"
EventHandler::~EventHandler()
{
instance = nullptr;
}
void EventHandler::Initialize()
{
instance = this;
}
void EventHandler::Run()
{
//TODO: Determine the Event and cast or instantiate to the right class
IEvent* evnt = events.front; //This should not be IEvent*, but Event<>*
events.pop();
listeners[evnt->id].exec(evnt->arguments); //The delegate may need to be casted too.
}
void EventHandler::Shutdown()
{
instance = nullptr;
}
Listeners::iterator& EventHandler::Register(ID id, IDelegate* listener)
{
Listeners::iterator iter = listeners.emplace(id, listener);
return iter;
}
void EventHandler::Deregister(Listeners::iterator& iterator)
{
listeners.erase(iterator);
}
void EventHandler::Post(IEvent* evnt)
{
events.emplace(evnt);
}
Когда я сталкиваюсь с проблемами, выясняю, какое событие я на самом деле использую в Run (). Если это возможно, я хотел бы сделать это без переключателя или чего-то подобного, поскольку это побеждает использование шаблонных классов. Я подумал, что указатель функции должен быть одной и той же сигнатурой, поскольку это упростит часть кода, но сделает систему менее гибкой.
Спасибо за любую помощь.