Event Notification System in C++
Design an event notification system in C++
Introduction:
The intention of the design to provide the simple generic EventNotifier class which is responsible for handling the event notification functionality for the complete system. EventNotifier object notifies the events between different objects.
This design provides the communication mechanism between the objects when one object is depending on the state information from another object (or) object is expecting the data from other object (like timer expire notification).
This design provides the lose coupling between the listener object and notifier object. Both objects doesn't need to know each other and doesn't hold the instance of it. EventNotifier object is the mediator of these two objects.
Listener/Observer objects will register for the events which it is interested into. EventNotifier object holds the data of event list and corresponding registered listeners. Notifier object sends the notification to the EventNotifier object, and EventNotifier notify the events to corresponding listener objects.
Functionality:
Implementation:
Event list enumeration. All the signals/events added here.
enum eEventsList{
EVENT_INVALID = 0,
EVENT_TIMER_EXPIRED,
EVENT_TIMER_FIRED
};
Listener id enumeration. Each listener class assigned with unique ID value which is used in the EventNotifier class to map the function callback.
/* Listener ID*/
enum ListenersId
{
LISTENER_INVALID = 0,
LISTENER_TIMER //Timer class
};
1.EventNotifier class:
- This class contains the list of listenerID and corresponding function callbacks.
- This class contains mapping data between list of events and corresponding listeners.
/* Event Notifier */
class CEventNotifier
{
private:
//static instance
static shared_ptr<CEventNotifier> pEventNotifier;
//List of listeners, this listerner map contains the listener id and corresponding function callback
std::map<ListenersId, IEventConsumer*> listenersList;
//Create list which has map tp events and corresponding listerners
std::unordered_multimap<eEventsList, ListenersId> eventListeners;
public:
static shared_ptr<CEventNotifier> getEventNotifier();
void registerListener(ListenersId listenerId, IEventConsumer* fn, vector< eEventsList> eventsList);
void notifyEvent(eEventsList eventId, IEventdata* eventData);
void unregisterListener(ListenersId listenerId);
};
2. Interface class:
Any class can be a listener class, and each listener object is different data type. To provide the generic callback function, defined IEventConsumer interface class.
The purpose of this interface to provide the generic callback function to process the events. All the listener classes should inherit IEventConsumer and provide override function of processEvents (callback function) . This class invokes the registerListener function in the constructor.
/*Event consumer interface */
class IEventConsumer
{
public:
IEventConsumer(ListenersId listernerId, vector< eEventsList> eventsList)
{
shared_ptr<CEventNotifier> pNotifier = CEventNotifier::getEventNotifier();
//Call registerListener function to store the interested events and callback function
pNotifier->registerListener(listernerId, (this), eventsList);
}
virtual void processEvents(eEventsList id, IEventdata* eventData) = 0;
};
3. EventData class:
Each publisher object sends different type of data while sending the event. To provide the generic function which accepts different data type, defined the interface class for event data transmission.
class IEventdata
{
public:
virtual void* getdata() = 0;
virtual void release() = 0;
};
template<typename T>
class CEventdata: public IEventdata
{
T* data;
public:
explicit CEventdata(T* eventInfo)
{
data = eventInfo;
}
void* getdata() override
{
return static_cast<void*>(data);
}
void setdata(T* newdata)
{
data = newdata;
}
void release() override
{
if (data)
delete data;
}
};
4. Listener/Observer Class:
Observer class inherit from IEventConsumer class. This class should provide the override function for
void processEvents(eEventsList id, IEventdata* eventData) override. In the constructor function, it provides the list of events to listen and, listenerID. These listener classes has unique listenerID which is defined in the enum listenerID.
//Sample listener class:
/* Watchdog class */
class CWatchDog :public IEventConsumer
{
public:
//Constructor.
//Provide the list of interested events while calling the IEventConsumer constructor.
CWatchDog() : IEventConsumer(LISTENER_WATCHDOG, { EVENT_TIMER_EXPIRED, EVENT_TIMER_FIRED })
{
}
/* defined the callback function to process incoming events */
void processEvents(eEventsList id, IEventdata* eventData) override
{
cout << "callback triggered for " << id << endl;
CTimer::timerdata* data = static_cast<CTimer::timerdata*> (eventData->getdata());
cout << " timer data expired = " << data->timerExpired << " handle = " << data->timerId << endl;
}
};
5. Publisher/Notifier class:
Publisher class has the instance of EventNotifier object.
If this object wants to notify any data to other objects, it will invoke the notifyEvent(0 function from EventNotifier object along with the eventID and event data. EventNotifier will send the event to corresponding listener by invoking processEvents() function.
//Sample notifier class:
/* Timer class */
class CTimer
{
/* Get the instance of CEventNotifier */
shared_ptr<CEventNotifier> notifier;
public:
/*timer data */
struct timerdata
{
int timerId;
bool timerExpired;
timerdata(int id, bool status)
{
timerId = id;
timerExpired = status;
}
};
//constructor
CTimer()
{
notifier = CEventNotifier::getEventNotifier();
}
//Created for testing purpose.Sample funtion to show how to send events.
void executeAllCases()
{
//sending events to EventNotifier
timerdata *data = new timerdata(10, false);
CEventdata<timerdata>* pRet = new CEventdata<timerdata>(data);
notifier->notifyEvent(EVENT_TIMER_FIRED, static_cast<IEventdata*>(pRet));
data = new timerdata(10, true);
pRet = new CEventdata<timerdata>(data);
notifier->notifyEvent(EVENT_TIMER_EXPIRED, static_cast<IEventdata*>(pRet));
}
};
Unit testing:
/*Unit Testing */
int main()
{
//Create listener class objects
CWatchDog* watchDog = new CWatchDog();
CSensor* sensor = new CSensor();
//Create publisher class objects
CAlarm* alramPublisher = new CAlarm();
alramPublisher->executeAllCases();
CTimer* timerPublisher = new CTimer();
timerPublisher->executeAllCases();
return 0;
}
Complete project Github path : design_programs_in_c-/EventManager at main · krishnaKSA/design_programs_in_c- (github.com)