Observer Pattern
(from Design
Patterns)
Synopsis
Define a one-to-many dependency between objects so that when one object
changes state, all its dependents are notified and updated automatically.
Context
You want to maintain consistency between related objects, e.g. data and its
visual representation, a filesystem and its cache, or a 3D sphere and the
cube which is constrained to abut it.
Forces
-
You want to develop the objects separately, to minimize coupling (what they
know about eachother) and increase reuse (using one without the other).
-
There may be several observers for each subject, with the precise
configuration unknown at compile-time.
Solution
Equip the subject with an interface for subscribing and unsubscribing to
change notifications. Also include an interface for querying the subject,
so that observers can get the information they need. Equip the observers
with an interface for receiving the notifications from the subject.
When the subject is modified, it will notify its subscribers of a change,
who will then have the opportunity to query the subject for details and
update themselves.
Consequences
-
Low coupling because the subject does not need to know exactly what
information the observers need.
-
The number of observers per subject and the number of subjects per observer
can vary at run-time.
-
Efficiency may suffer because of spurious notifications. See
Implementation for remedies.
Implementation
For maximum speed, each subject can store references to its observers.
However, this wastes space when a subject has no observers. For minimum
space, you can use a global table of (subject, observer) pairs.
Before an observer can be deleted, it must unsubscribe from its subjects,
to avoid dangling pointers. Garbage-collected languages are not
exempt from this requirement.
Several variations are possible for reducing communication:
-
Each observer can specify what aspect of the subject it is interested in.
The subject can then only notify observers interested in the particular
change.
-
Instead of simply notifying the observers of a change, the subject could
also broadcast the details of the change. This only pays off if the
observers really need the details, so it is usually paired with the above
"interest" mechanism.
-
If the subject is in charge of triggering notification, then when multiple
successive modifications are made, each one will fire a salvo of messages
to the observers. This is particularly bad if the sequence of
modifications is intended to be atomic, e.g. if the intermediate states are
inconsistent. An alternative is to put the modifying party in charge of
triggering notification after all modifications are done.
-
When the subject is not one object but rather a web of objects,
many spurious notifications may be created as changes propagate through the
web. One way to avoid this is to use a separate change manager
object which batches all of the changes, notifying each observer exactly
once.
-
To catch cyclic dependencies, each notification can have a timestamp.
Notifications which are the result of other notifications share the same
timestamp. If an observer receives a notification with the same timestamp as
one it sent out, then it does not continue the propagation. In other
words, no object sends two separate notifications with the same timestamp.
See Design
Patterns or this page for sample
code.
Known Uses
-
MFC, ET++, and Smalltalk use the Observer pattern in separating Documents
(or Models) and Views.
-
Smalltalk and ET++ equip all objects with both subject and observer
interfaces.
-
CORBA has an entire subsystem for event notification between distributed
objects. The change manager technique is used between compound documents.
ActiveX has similar facilities. This is why you can link cells in
different Excel spreadsheets.
-
Cache-coherent multiprocessors like the SGI Challenge use the Observer
pattern to keep processor caches consistent. The Andrew File System uses
it to keep file caches consistent. NFS does not use the Observer
pattern; caches simply flush themselves periodically.
-
Inventor uses the Observer pattern to enforce equality between linked
fields of scene nodes. It uses the timestamp trick to allow cycles.
-
The X Window System uses event notification, but not with objects.
Each window registers its interest in particular events, and all
relevant information is directly sent to a callback when the event occurs.
Languages based on constraints generally do not use the Observer pattern,
because local propagation is inefficient for complex constraints and is
susceptible to cycles. Instead, such languages use a centralized
constraint solver.
Exercise
Suppose an observer initiates a modification to its subject, as is common
with Documents and Views. The subject will then notify the observer of a
change it already knows about. Can and should this spurious notification
be avoided?
Thomas Minka
Last modified: Thu Jan 23 13:06:02 EST 1997