The Subject-Observer Pattern
The subject-observer pattern defines a one-to-many dependency between objects, so that when one object changes state, all its dependents are notified and updated automatically. In the subject-observer relationship, a subject encapsulates related data and functionality that an observer monitors. If the state of the subject changes, the observer needs to know about it. To accomplish this, the subject defines a notification dictionary that is the set of all notifications of change a subject may broadcast. A notification is any class that implements the IMessage interface. It is the responsibility of the subject to define a notification dictionary and to broadcast individual notifications of change to its list of observers. It is the responsibility of the observer to subscribe to the notifications sent by a subject and to understand and react to the notifications it receives.
A subject is any class that implements the ISubject interface, shown in Example 7.
Example 7 – The ISubject interface
class ISubject : public IQueryGuid, public IRefCount
virtual void AddObserver(IObserver* pObserver) = 0;
virtual void RemoveObserver(IObserver* pObserver) = 0;
virtual void UpdateAllObservers(IObserver* pObserver,
IMessage* pMsg) = 0;
The AddObserver() method allows observers to subscribe to notifications sent by the subject. The RemoveObserver() method removes a particular observer from the subject. The UpdateAllObservers() method sends a notification message to all observers.
A notification message is any class that implements the IMessage interface, shown in Example 8.
Example 8 – The IMessage interface
class IMessage : public IQueryGuid, public IRefCount
virtual unsigned int GetTypeID() const = 0;
virtual void Sprint(CString& strCmd) = 0;
Each message type is associated with an integer identifier, which can be used by observers to identify the message given an IMessage pointer. It is also possible to use QueryGuid() or the guid_cast operator to cast an IMessage pointer to another type.
The IObserver interface, shown in Example 9, is implemented by classes that need to observe subjects.
Example 9 – The IObserver interface
class IObserver : public IQueryGuid, public IRefCount
virtual void OnUpdate(ISubject* pSubject, IMessage* pMsg) = 0;
The subject invokes the OnUpdate() method to send notification messages to observers. Subjects typically implement the UpdateAllObservers() method by iterating over each observer and calling their OnUpdate() method.
An object can implement both the ISubject and IObserver interfaces, producing an object that observes one object and acts as a subject for others. This makes it possible to chain together or nest subjects and observers.