Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Dependents, Publish-Subscribe
A common side-effect of partitioning a system into a collection of cooperating classes is the need to maintain consistency between related objects. You don't want to achieve consistency by making the classes tightly coupled, because that reduces their reusability.
For example, many graphical user interface toolkits separate the presentational aspects of the user interface from the underlying application data [KP88, LVC89, P+88, WGM88]. Classes defining application data and presentations can be reused independently. They can work together, too. Both a spreadsheet object and bar chart object can depict information in the same application data object using different presentations. The spreadsheet and the bar chart don't know about each other, thereby letting you reuse only the one you need. But they behave as though they do. When the user changes the information in the spreadsheet, the bar chart reflects the changes immediately, and vice versa.
This behavior implies that the spreadsheet and bar chart are dependent on the data object and therefore should be notified of any change in its state. And there's no reason to limit the number of dependent objects to two; there may be any number of different user interfaces to the same data.
The Observer pattern describes how to establish these relationships. The key objects in this pattern are subject and observer. A subject may have any number of dependent observers. All observers are notified whenever the subject undergoes a change in state. In response, each observer will query the subject to synchronize its state with the subject's state.
This kind of interaction is also known as publish-subscribe. The subject is the publisher of notifications. It sends out these notifications without having to know who its observers are. Any number of observers can subscribe to receive notifications.
Use the Observer pattern in any of the following situations:
The following interaction diagram illustrates the collaborations between a subject and two observers:
Note how the Observer object that initiates the change request postpones its update until it gets a notification from the subject. Notify is not always called by the subject. It can be called by an observer or by another kind of object entirely. The Implementation section discusses some common variations.
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.
Further benefits and liabilities of the Observer pattern include the following:
Because Subject and Observer aren't tightly coupled, they can belong to different layers of abstraction in a system. A lower-level subject can communicate and inform a higher-level observer, thereby keeping the system's layering intact. If Subject and Observer are lumped together, then the resulting object must either span two layers (and violate the layering), or it must be forced to live in one layer or the other (which might compromise the layering abstraction).
This problem is aggravated by the fact that the simple update protocol provides no details on what changed in the subject. Without additional protocol to help observers discover what changed, they may be forced to work hard to deduce the changes.
Several issues related to the implementation of the dependency mechanism are discussed in this section.
This self-consistency rule is easy to violate unintentionally when Subject subclass operations call inherited operations. For example, the notification in the following code sequence is trigged when the subject is in an inconsistent state:
void MySubject::Operation (int newValue) { BaseClassSubject::Operation(newValue); // trigger notification _myInstVar += newValue; // update subclass state (too late!) }
You can avoid this pitfall by sending notifications from template methods (Template Method (325)) in abstract Subject classes. Define a primitive operation for subclasses to override, and make Notify the last operation in the template method, which will ensure that the object is self-consistent when subclasses override Subject operations.
void Text::Cut (TextRange r) { ReplaceRange(r); // redefined in subclasses Notify(); }
By the way, it's always a good idea to document which Subject operations trigger notifications.
At one extreme, which we call the push model, the subject sends observers detailed information about the change, whether they want it or not. At the other extreme is the pull model; the subject sends nothing but the most minimal notification, and observers ask for details explicitly thereafter.
The pull model emphasizes the subject's ignorance of its observers, whereas the push model assumes subjects know something about their observers' needs. The push model might make observers less reusable, because Subject classes make assumptions about Observer classes that might not always be true. On the other hand, the pull model may be inefficient, because Observer classes must ascertain what changed without help from the Subject.
void Subject::Attach(Observer*, Aspect& interest);
where interest
specifies the event
of interest. At notification time, the subject supplies the changed
aspect to its observers as a parameter to the Update operation. For
example:
void Observer::Update(Subject*, Aspect& interest);
ChangeManager has three responsibilities:
The following diagram depicts a simple ChangeManager-based implementation of the Observer pattern. There are two specialized ChangeManagers. SimpleChangeManager is naive in that it always updates all observers of each subject. In contrast, DAGChangeManager handles directed-acyclic graphs of dependencies between subjects and their observers. A DAGChangeManager is preferable to a SimpleChangeManager when an observer observes more than one subject. In that case, a change in two or more subjects might cause redundant updates. The DAGChangeManager ensures the observer receives just one update. SimpleChangeManager is fine when multiple updates aren't an issue.
ChangeManager is an instance of the Mediator (273) pattern. In general there is only one ChangeManager, and it is known globally. The Singleton (127) pattern would be useful here.
An abstract class defines the Observer interface:
class Subject; class Observer { public: virtual ~ Observer(); virtual void Update(Subject* theChangedSubject) = 0; protected: Observer(); };
This implementation supports multiple subjects for each observer. The
subject passed to the Update
operation lets the observer
determine which subject changed when it observes more than one.
Similarly, an abstract class defines the Subject interface:
class Subject { public: virtual ~Subject(); virtual void Attach(Observer*); virtual void Detach(Observer*); virtual void Notify(); protected: Subject(); private: List<Observer*> *_observers; }; void Subject::Attach (Observer* o) { _observers->Append(o); } void Subject::Detach (Observer* o) { _observers->Remove(o); } void Subject::Notify () { ListIterator<Observer*> i(_observers); for (i.First(); !i.IsDone(); i.Next()) { i.CurrentItem()->Update(this); } }
ClockTimer
is a concrete subject for storing and
maintaining the time of day. It notifies its observers every second.
ClockTimer
provides the interface for retrieving individual
time units such as the hour, minute, and second.
class ClockTimer : public Subject { public: ClockTimer(); virtual int GetHour(); virtual int GetMinute(); virtual int GetSecond(); void Tick(); };
The Tick
operation gets called by an internal timer at
regular intervals to provide an accurate time base. Tick
updates the ClockTimer
's internal state and calls
Notify
to inform observers of the change:
void ClockTimer::Tick () { // update internal time-keeping state // ... Notify(); }
Now we can define a class DigitalClock
that displays the
time. It inherits its graphical functionality from a Widget
class provided by a user interface toolkit. The Observer interface is
mixed into the DigitalClock
interface by inheriting from
Observer
.
class DigitalClock: public Widget, public Observer { public: DigitalClock(ClockTimer*); virtual ~DigitalClock(); virtual void Update(Subject*); // overrides Observer operation virtual void Draw(); // overrides Widget operation; // defines how to draw the digital clock private: ClockTimer* _subject; }; DigitalClock::DigitalClock (ClockTimer* s) { _subject = s; _subject->Attach(this); } DigitalClock:: DigitalClock () { _subject->Detach(this); }
Before the Update
operation draws the clock face, it checks
to make sure the notifying subject is the clock's subject:
void DigitalClock::Update (Subject* theChangedSubject) { if (theChangedSubject == _subject) { Draw(); } } void DigitalClock::Draw () { // get the new values from the subject int hour = _subject->GetHour(); int minute = _subject->GetMinute(); // etc. // draw the digital clock }
An AnalogClock
class can be defined in the same way.
class AnalogClock : public Widget, public Observer { public: AnalogClock(ClockTimer*); virtual void Update(Subject*); virtual void Draw(); // ... };
The following code creates an AnalogClock
and a
DigitalClock
that always show the same time:
ClockTimer* timer = new ClockTimer; AnalogClock* analogClock = new AnalogClock(timer); DigitalClock* digitalClock = new DigitalClock(timer);
Whenever the timer
ticks, the two clocks will be updated
and will redisplay themselves appropriately.
The first and perhaps best-known example of the Observer pattern appears in Smalltalk Model/View/Controller (MVC), the user interface framework in the Smalltalk environment [KP88]. MVC's Model class plays the role of Subject, while View is the base class for observers. Smalltalk, ET++ [WGM88], and the THINK class library [Sym93b] provide a general dependency mechanism by putting Subject and Observer interfaces in the parent class for all other classes in the system.
Other user interface toolkits that employ this pattern are InterViews [LVC89], the Andrew Toolkit [P+88], and Unidraw [VL90]. InterViews defines Observer and Observable (for subjects) classes explicitly. Andrew calls them "view" and "data object," respectively. Unidraw splits graphical editor objects into View (for observers) and Subject parts.
Mediator (273): By encapsulating complex update semantics, the ChangeManager acts as mediator between subjects and observers.
Singleton (127): The ChangeManager may use the Singleton pattern to make it unique and globally accessible.