A C++ MVC framework I’m writing makes heavy use of the observer pattern. I have had a thorough read of the related chapter in Design Patterns (GoF, 1995) and had a look at a multitude of implementations in articles and existing libraries (including Boost).
But as I was implementing the pattern, I could not help the feeling that there must be a better way - my client code involved lines and snippets that I felt should have been refactored into the pattern itself, if only I could find a way to overcome a few C++ limitations. Also, my syntax never appeared as elegant as that used in the ExtJs library:
// Subscribing
myGridPanel.on( 'render', this.onRender );
// Firing
this.fireEvent( 'render', null, node );
So I decided to conduct further research in attempt to arrive at a generalised implementation, while prioritizing code elegancy, readability and performance. I believe I've hit the jackpot on the 5th attempt.
The actual implementation, called gxObserver
, is available on GitHub; it is well-document and the readme files spell out the pros as well as the cons. Its syntax is:
// Subscribing
mSubject->gxSubscribe( evAge, OnAgeChanged );
// Firing
Fire( evAge, 69 );
Having done what turned into an excessive work, I felt it would be just to share my findings with the SO community. So below I will answer this question:
What additional considerations (to these presented in Design Patterns) should programmers account for when implementing the observer pattern?
While focused around C++, many of the written below will apply in any language.
Please note: As SO limits answers to 30000 words, my answer had to be provided in 2 parts, but sometimes the second answer (the one starting with 'Subjects' shows up) first. Part 1 of the answer is the one starting with the class diagram from Design Patterns.
Consequences. The Observer pattern lets you vary subjects and observers independently. You can reuse subjects without reusing their observers, and vice versa. It lets you add observers without modifying the subject or other observers.
In software design and engineering, the observer pattern is a software design pattern in which an object, named the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
Observer is a behavioral design pattern. It specifies communication between objects: observable and observers. An observable is an object which notifies observers about the changes in its state. For example, a news agency can notify channels when it receives news.
Disadvantages of Observer Design Pattern The main disadvantage of the observer design pattern that subscribers are notified in random order. There is also a memory leakage problem in the observer design pattern because of the observer's explicit register and unregistering.
(start of part II)
Depending on the specific implementation, subjects may store the following data when observers subscribe:
This data will form the parameters of the subscribe method:
// Subscription with an overridden handler (where the observer class has a base class handler method).
aSubject->Subscribe( "SizeChanged", this );
// Subscription with an arbitrary handler.
aSubject->Subscribe( "SizeChanged", this, &ThisObserverClass::OnSizeChanged );
It is worth noting that if arbitrary handler are used, member function pointers are likely to be packed together with the observer instance in a class or a struct to form a delegate. And so the Subscribe()
method might have the following signature:
// Delegate = object pointer + member function pointer.
void Subject::Subscribe( EventId aEventId, Delegate aDelegate )
{
//...
}
The actual storing (possibly within a std::map
) will involve the event id as the key and the delegate as the value.
Defining event IDs outside the subject class that fires them could simplify the access to these IDs. But generally speaking, the events fired by a subject are unique to that subject. Thus, in most cases it will be logical to declare the event IDs within the subject class.
Although there are more than a few ways to declare event IDs, only 3 that are of most interest are discussed here:
Enums seem, on the face of it, the most logical choice:
class FigureSubject : public Subject
{
public:
enum {
evSizeChanged,
evPositionChanged
};
};
The comparison of enums (which will happen upon subscription and firing) is quick. Perhaps the only inconvenience with this strategy is that observers need to specify the class upon subscription:
// 'FigureSubject::' is the annoying bit.
aSubject->Subscribe( FigureSubject::evSizeChanged, this );
Strings provide a 'looser' option to enums, as typically the subject class will not declare them like enums; instead, clients will just use:
// Observer code
aFigure->Subscribe( "evSizeChanged", this );
The nice thing about strings is that most compilers colour code them differently from other parameters, which somehow improves the readability of the code:
// Within a concrete subject
Fire( "evSizeChanged", mSize, iOldSize );
But the issue with strings is that we cannot tell at runtime if we have misspelled an event name. Also, string comparison takes longer than enum comparison, as strings have to be compared character by character.
Types is the last option discussed here:
class FigureSubject : public Subject
{
public:
// Declaring the events this subject supports.
class SizeChangedEventType : public Event {} SizeChangedEvent;
class PositionChangedEventType : public Event {} PositionChangedEvent;
};
The benefit of using types is that they allow the overloading of methods like Subscribe()
(which we'll soon see can solve a common problem with observers):
// This particular method will be called only if the event type is SizeChangedType
FigureSubject::Subscribe( SizeChangedType aEvent, void *aObserver )
{
Subject::Subscribe( aEvent, aObserver );
Fire( aEvent, GetSize(), aObserver );
}
But again, observers need a bit of extra code to subscribe:
// Observer code
aFigure->Subscribe( aFigure->SizeChangedEvent, this );
Implementation point 1 in Design Pattern deals with where should the observers of each subject be stored. This section adds to that discussion, providing 3 options:
As suggested in Design Patterns, one place to store the subject-observer map is in a global hash table. The table will include the subject, the event and the observer (or delegate). Of all methods, this one is the most memory efficient as subjects don’t consume a member variable to store the list of observers in – there is only one global list. This could be useful if the pattern is implemented in javascript frameworks due to the limited memory offered by browsers. The main disadvantage of this method is that it is also the slowest – for every event being fired, we first have to filter the requested subject from the global hash, then filter the requested event, and only then iterate through all observers.
Also suggested in Design Patterns is that every subject keeps a list of its observers. This will consume slightly more memory (in the form of an std::map
member variable per subject), but it provides better performance than a global hash as the subject only need to filter the requested event, then iterate through all the observers of this event. The code may look like so:
class Subject
{
protected:
// A callback is represented by the event id and the delegate.
typedef std::pair< EventId, Delegate > Callback;
// A map type to store callbacks
typedef std::multimap< EventId, Delegate > Callbacks;
// A callbacks iterator
typedef Callbacks::iterator CallbackIterator;
// A range of iterators for use when retrieving the range of callbacks
// of a specific event.
typedef std::pair< CallbackIterator, CallbackIterator> CallbacksRange;
// The actual callback list
Callbacks mCallbacks;
public:
void Fire( EventId aEventId )
{
CallbacksRange iEventCallbacks;
CallbackIterator iIterator;
// Get the callbacks for the request event.
iEventCallbacks = mCallbacks.equal_range( aEventId );
for ( iIterator = iEventCallbacks.first; iIterator != iEventCallbacks.second; ++iIterator )
{
// Do the firing.
}
}
};
Not suggested in Design Patterns is the option of having each event as a member variable, then store observers within the event itself. This is the most memory consuming strategy as not only each event consumes a member variable, but there’s also an std::vector
storing observers per event. However, this strategy provides best performance as there’s no filtering to be done and we can just iterate through the attached observers. This strategy will also involve the most simplistic code compared to the other two. To implement it, an event will have to offer subscription and fire methods:
class Event
{
public:
void Subscribe( void *aDelegate );
void Unsubscribe( void *aDelegate );
void Fire();
};
The subject may look something like so:
class ConcreteSubject : public Subject
{
public:
// Declaring the events this subject supports.
class SizeChangedEventType : public Event {} SizeChangedEvent;
class PositionChangedEventType : public Event {} PositionChangedEvent;
};
Although observers could theoretically subscribe to the events directly, we’ll see that it pays to go through the subject instead:
// Subscribing to the event directly - possible but will limit features.
aSubject->SizeChangedEvent.Subscribe( this );
// Subscribing via the subject.
aSubject->Subscribe( aSubject->SizeChangedEvent, this );
The 3 strategies provide a clear case of the store-vs-compute tradeoff. And can be compared using the following table:
The approach taken should account for the following:
When the observer pattern is used to notify MouseMove
events, one may want to consider more the performance of the implementation. As far as memory penalties go, the following calculation may help. Given:
8 million subject instances will consume just below 1GB of RAM (events memory only).
One key question in the implementation of the observer pattern is whether or not we allow the same observer to subscribe more than once to the same event (of the same subject).
To begin with, if we do allow it we are likely to use std::multimap
instead of std::map
. In addition, the following line will be problematic:
aSubject->Unsubscribe( evSizeChanged, this );
Since there is no way for the subject to know which of the previous subscriptions (there can be more than one!) to unsubscribe from. So Subscribe()
will have to return a token that Unsubscribe()
will use, and the whole implementation gets far more complex.
On the face of it, it seems rather idiotic – why would the same object like to subscribe to the same event more than once? But consider the following code:
class Figure
{
public:
Figure( Subject *aSubject )
{
// We subscribe to the subject on size events
aSubject->Subscribe( evSizeChanged, this, &Figure::OnSizeChanged );
}
void OnSizeChanged( Size aSize )
{
}
};
class Circle : public Figure
{
public:
Circle( Subject *aSubject )
: Figure( aSubject)
{
// We subscribe to the subject on size events
aSubject->Subscribe( evSizeChanged, this, &Circle::OnSizeChanged );
}
void OnSizeChanged( Size aSize )
{
}
};
This particular code will lead to the same object subscribing to the same event twice. It is also worth noticing that since the OnSizeChanged()
method is not virtual, the member function pointer will be different between the two subscription calls. So in this particular case the subject could also compare the member function pointer, and the unsubscribe signature will be:
aSubject->Unsubscribe( evSizeChanged, this, &Circle::OnSizeChanged );
But if the OnSizeChanged()
is virtual, there is no way to distinguish between the two subscription calls without a token.
Truth to be told, if OnSizeChanged()
is virtual, there is no reason for the Circle
class to subscribe to the event again since it is its own handler that will be called and not that of the base class:
class Figure
{
public:
// Constructor
Figure( Subject *aSubject )
{
// We subscribe to the subject on size events
aSubject->Subscribe( evSizeChanged, this, &Figure::OnSizeChanged );
}
virtual void OnSizeChanged( Size aSize )
{
}
};
class Circle : public Figure
{
public:
// Constructor
Circle( Subject *aSubject )
: Figure( aSubject) { }
// This handler will be called first when evSizeChanged is fired.
virtual void OnSizeChanged( Size aSize )
{
// And we can call the base class handler if we want.
Figure::OnSizeChanged( aSize );
}
};
This code probably represents the best compromise when it comes to both the base class and its subclass having to respond to the same event. But it requires the handlers to be virtual and the programmer to know which events the base class subscribes to.
Disallowing the same observer to subscribe more than once to the same event greatly simplifies the implementation of the pattern. It saves the need to compare member function pointers (a tricky business) and it allows Unsubscribe()
to be as short as this (even if an MFP was provided with Subscribe()
):
aSubject->Unsubscribe( evSizeChanged, this );
One of the prime aims of the observer pattern is to keep observers consistent with their subject state – and we have already seen that state change events do exactly that.
It is somewhat surprising that it went amiss to the authors of Design Patterns to assert that when an observer subscribes to a subject, the state of the former is not yet consistent with the state of the latter. Consider this code:
class Figure
{
public:
// Constructor
Figure( FigureSubject *aSubject )
{
// We subscribe to the subject on size events
aSubject->Subscribe( evSizeChanged, this, &Figure::OnSizeChanged );
}
virtual void OnSizeChanged( Size aSize )
{
mSize = aSize;
// Refresh the view.
Refresh();
}
private:
Size mSize;
};
Upon creation, the Figure
class does subscribe with its subject, but its size is not consistent with that of the subject, nor it will refresh the view to display what should be its correct size.
When the observer pattern is used to fire state change event, one will often find the need to update the observers manually after subscription. One way to achieve this is within the observer:
class Figure
{
public:
Figure( FigureSubject *aSubject )
{
// We subscribe to the subject on size events
aSubject->Subscribe( evSizeChanged, this, &Figure::OnSizeChanged );
// Now make sure we're consistent with the subject.
OnSizeChanged( aSubject->GetSize() );
}
// ...
};
But imagine a subject with 12 state change events. It would be nice if the whole thing would happen automatically, where upon subscription the subject will fire the correct event back to the observer.
One way to achieve this requires an overloaded Subscribe()
method in the concrete subject:
// This method assumes that each event has its own unique class, so the method
// can be overloaded.
FigureSubject::Subscribe( evSizeChanged aEvent, Delegate aDelegate )
{
Subject::Subscribe( aEvent, aDelegate );
// Notice the last argument in this call.
Fire( aEvent, GetSize(), aDelegate );
}
Then the observer code:
class Figure
{
public:
Figure( FigureSubject *aSubject )
{
// We subscribe to the subject on size events.
// The subject will fire the event upon subscription
aSubject->Subscribe( evSizeChanged, MAKEDELEGATE( this, &Figure::OnSizeChanged ) );
}
// ...
};
Notice that the Fire
call now takes an extra parameter (aDelegate
) so it can only update that specific observer and not observers already subscribed.
gxObserver deals with this scenario by defining bound events. These are events whose only parameter (other than an optional sender) is bound to a getter or a member variable:
class Subject : virtual public gxSubject
{
public:
gxDefineBoundEvent( evAge, int, GetAge() )
int GetAge() { return mAge; }
private:
int mAge;
}
Which also allows subjects to fire an event providing only the event type:
// Same as Fire( evAge, GetAge() );
Fire( evAge );
Regardless of the mechanism used, it is worth remembering:
Fire()
method may need an extra optional parameter so it can fire to a single observer (the one that just subscribed).The following code snippet shows the implementation of event firing in JUCE:
void Button::sendClickMessage (const ModifierKeys& modifiers)
{
for (int i = buttonListeners.size(); --i >= 0;)
{
ButtonListener* const bl = (ButtonListener*) buttonListeners[i];
bl->buttonClicked (this);
}
}
There are a few issues with this approach:
buttonListeners
, which would imply it also has its own AddListener
and RemoveListener
methods.ButtonListener
) and the actual callback method within it (buttonClicked
).All these points mean that there is no base subject class. If taking this approach, any firing/subscription mechanism will have to be re-implemented per each concrete subject. This is counter object oriented programming.
It would be sensible to have the observers’ management, their traversal, and the actual notification done in a subject base class; this way, any changes to the underlining mechanism (introducing thread-safety, for instance) would not require a change in each concrete subject. This will leave our concrete subjects with a well-encapsulated and simple interface, and firing is reduced to one line:
// In a concreate subject
Fire( evSize, GetSize() );
Many applications and frameworks will find the need to suspend the firing of events for a specific subject. Sometimes we’d like the suspended events to queue up and be fired when we resume firing, sometimes we just want to ignore them. As far as the subject interface goes:
class Subject
{
public:
void SuspendEvents( bool aQueueSuspended );
void ResumeEvents();
};
One example to where event suspension is useful is during the destruction of composite objects. When a composite object is being destroyed, it first destroys all of its children, which first destroy all of their children, and so on. Now if these composite objects reside in the model layer, they’ll need to notify their corresponding objects in the view layer (say using an evBeforeDestroy
event):
Now in this specific case there is no need for each object to fire an evBeforeDestroy
event – it will do if only the top-level model object will (deleting the top-level view object will also delete all its children). So whenever a composite as such is destroyed, it would like to suspend the events of its children (without queuing them).
Another example would be the loading of document involving many objects, some observe others. While a subject may load first and have its size set based on the file data, its observers may not yet be loaded and thus would not get the size change notification. In this case, we’d like to suspend events before load, but queue them until the document was loaded in full. Firing all queued events then will ensure all observers are consistent with their subjects.
Lastly, an optimised queue will not queue the same event for the same subject more than once. When notifications resume, there is no point notifying observers of a size change to (10,10) if a later queued event will notify (20,20). So the most recent version of each event is the one the queue should keep.
A typical subject interface would look something along these lines:
class Subject
{
public:
virtual void Subscribe( aEventId, aDelegate );
virtual void Unsubscribe( aEventId, aDelegate );
virtual void Fire( aEventId );
}
The question is how do we add this interface to various classes. There are three options to consider:
In Design Patterns, a ConcreteSubject
class inherits from a Subject
class.
class ScrollManager: public Subject
{
}
Both the class diagrams and sample code in Design Pattern could easily leave one thinking that this is how to go about it. But the very same book warns against inheritance and recommends favouring composition over it. This is sensible: consider an application with many composites where only some are subjects; shall the Composite
class inherit from the Subject
class? If so, many composites will have subject capabilities they don’t need, and there may a memory penalty in the form of an observer list variable that is always empty.
Most applications and frameworks will find the need to ‘plug’ the subject capabilities only into selected classes, which are not necessarily base classes. Composition allows exactly that. In practice, a class will have a member mSubject
providing interface to all the subject methods, like so:
class ScrollManager: public SomeObject
{
public:
Subject mSubject;
}
One issue with this strategy is that it carries memory penalty (a member variable) for each subject-supported class. The other is that it makes accessing the subject protocol somewhat cumbersome:
// Notification within a class composed with the subject protocol.
mSubject.Fire( ... );
// Or the registration from an observer.
aScrollManager.mSubject.Subscribe( ... );
Multiple Inheritance allows us to compose the subject protocol into a class at will, but without the pitfalls of member composition:
class ScrollManager: public SomeObject,
public virtual Subject
{
}
This way, we are getting rid of mSubject
from the previous example, so we’re left with:
// Notification within a subject class.
Fire( ... );
// Or the registration from an observer.
aScrollManager.Subscribe( ... );
Notice that we use public virtual
for the subject inheritance, so if subclasses of ScrollManager
decide to re-inherit the protocol, we don’t get the interface twice. But it is fair to assume that programmers will notice that a base class is already a subject, thus there’s no reason to re-inherit it.
While multiple inheritance is generally not encouraged and not all languages support it, it is well worth considering for this purpose. ExtJs, which being based on Javascript does not support multiple inheritance, uses mixins to achieve the same thing:
Ext.define('Employee', {
mixins: {
observable: 'Ext.util.Observable'
},
constructor: function (config) {
this.mixins.observable.constructor.call(this, config);
}
});
To conclude this article, generalised implementations of the observer pattern should account to these key points:
(end of part II)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With