Introduction
This article gives an insight into Event Aggregator Pattern which is used in an Enterprise Application software. As pattern name itself indicates it deals with handling events in our software application. The pattern can be used in normal applications as well, and need not be restricted for Enterprise Applications.
To understand example program given with the article, I am assuming that reader is familiar with .Net Reflection and Thread synchronization concepts.
Background
An event in software application indicates occurrence of an important thing like change in objects state, components state, application state, etc. All software applications from small to large uses events to indicate changes happening to it and can become the backbone for its internal and external communication.
An event allows loose coupling between two or more objects that wants to communicate by allowing sender object [Publisher] to specify what event occurs when it's undergoing change and then allow multiple receiver objects [Subscriber(s)] to subscribe to it. The publisher object does not directly refer to the subscriber object and will not be aware of their existence and can undergo changes without effecting the subscribers as long as event related interfaces are not changed.
All software development frameworks like .NET or JAVA provides built in Event Handling mechanisms to create events, indicate event occurrence, allow other objects or components to register and unregister to event occurrence. Almost all User Interface (UI) frameworks rely heavily on Event Handling mechanism to develop UI objects that interacts with users.
The section below describes traditional event handling and its disadvantages as software application scales.
Traditional Event handling
The steps below describes Traditional Event Handling.
- Publisher advertises its event(s) and specifies when they will be invoked.
- A Subscriber will then register itself to Publisher event(s).
- As Publisher object undergoes changes in its lifetime it will invoke the event informing the Subscriber(s).
Disadvantages of Traditional Event handling
- If there are multiple Subscribers and Publishers then code become hard to read and debug.
- The Subscriber of the event needs to know the Publisher of an event and refer it directly by event names causing a tight coupling between them.
- The tight coupling will not allow Subscribers and Publishers to change independently of each other.
- Its Subscriber responsibility to register and unregister from an event, its seen many practical scenarios the subscriber typically forgets to unregister causing both subscriber and publisher to be in memory causing memory leaks.
Event Aggregator pattern
The Event Aggregator pattern tries overcome the limitation of traditional event handling approach by providing a central place to publish and subscribe for events which is nothing but an Event Aggregator. The Event Aggregator takes care for registering, unregistering and invoking of events loosely coupling Publishers and Subscribers. All Publishers and Subscribers of event will know only about the Event Aggregator. The diagram below shows a typical Event aggregator in an Application.
Intent of pattern
- Simplify subscribing and unsubscribing to events
- Decouple publishers from subscribers allowing both to change without effecting the other.
- Reduce wastage of system resources, but may depend on support from development framework or environment.
- Makes it easy to add new events.
- Centralized handling of events.
Using the code
There many ways to implement Event Aggregator pattern, and the way you implement may vary based on framework and language infrastructure used by your software development environment. The example program used by me is developed in .NET 4.0 framework using C# language I am heavily relying on Reflection and Generics for implementing my Event Aggregator.
To use Event Aggregator provided in example program follow the steps below.
Step 1 : Identify Events and their arguments in your application
In sample program I have three events related to item object along with their arguments as shown below.
public class ItemCreated
{
public Item Item { get; set; }
}
public class ItemSaved
{
public Item Item { get; set; }
}
public class ItemSelected
{
public Item Item { get; set; }
}
Step 2 : Create a single global instance of Event Aggregator
To allow Events to be subscribed and published create a single global instance of Event Aggregator in your application as shown below.
this.ea = new EventAggregator.EventAggregator();
This global instance must be made available to all Publishers and Subscribers in the application.
Step 3 : A Subscriber to subscribe to Events
To subscribe to an event the Subscriber needs to implement the ISubscriber<TEventType> interface where TEventType is type if even it's interested in that are identified in Step 1. The interface definition is given below:
public interface ISubscriber<TEventType>
{
void OnEventHandler(TEventType e);
}
In sample program ItemView User Control subcribes to all three events as shown below.
public partial class ItemView : UserControl
, ISubscriber<ItemSaved>, ISubscriber<ItemSelected>, ISubscriber<ItemCreated>
{
public ItemView(IEventAggregator ea)
{
InitializeComponent();
ea.SubsribeEvent(this);
}
#region ISubscriber<ItemSelected> Members
public void OnEventHandler(ItemSelected e)
{
this.Label.Content = string.Format("Item Selected {0}", e.Item.ItemNumber);
}
#endregion
#region ISubscriber<ItemSaved> Members
public void OnEventHandler(ItemSaved e)
{
this.Label.Content = string.Format("Item Saved {0}", e.Item.ItemNumber);
}
#endregion
#region ISubscriber<ItemSaved> Members
public void OnEventHandler(ItemCreated e)
{
this.Label.Content = string.Format("Item Created {0}", e.Item.ItemNumber);
}
#endregion
}
Step 4 : Publisher to publish the Events
To publish an event the Publisher needs to invoke IEventAggregator.PublishEvent<TEventType>(TEventType eventToPublish); method and pass instance of Event type identified in Step 1.
In sample program ItemListView User Control publishes ItemSaved event as shown below.
this.EventAggregator.PublishEvent(new ItemSaved() { Item = savedItem });
A peep under Event Aggregator hood
The Event Aggregator implements IEventAggregator interface. The interface definition is as given below:
public interface IEventAggregator
{
void PublishEvent<TEventType>(TEventType eventToPublish);
void SubsribeEvent(Object subscriber);
}
The Event Aggregator maintains an internal dictionary for each Event type with its invocation list as WeakReference.
When SubsribeEvent(Object subscriber) method is invoked by a Subscriber it uses reflection determine all ISubscriber<TEventType> types supported by that instance and keeps it in dictionary. The method is to be called only once for a subscriber typically in its constructor logic.
When PublishEvent<TEventType>(TEventType eventToPublish) method is invoked by a Publisher it gets the invocation list of instances who have subscribed to TEventType and invokes them if they are still active in the application or else removes them from invocation list.
Points of Interest
When Event Aggregator code is shown to .NET developers they get confused at times with traditional Events and Delegates approach normally used in .NET application.