26.10. Observer/Publish-Subscribe/Delegation Event Model (GoF)

Another requirement for the iteration is adding the ability for a GUI window to refresh its display of the sale total when the total changes (see Figure 26.21). The idea is to solve the problem for this one case, and then in later iterations, extend the solution to refreshing the GUI display for other changing data as well.

Figure 26.21. Updating the interface when the sale total changes.

Why not do the following as a solution? When the

Sale changes its total, the

Sale object sends a message to a window, asking it to refresh its display.

To review, the Model-View Separation principle discourages such solutions. It states that "model" objects (non-UI objects such as a

Sale ) should not know about view or presentation objects such as a window. It promotes Low Coupling from other layers to the presentation (UI) layer of objects.

A consequence of supporting this low coupling is that it allows the replacement of the view or presentation layer by a new one, or of particular windows by new windows, without impacting the non-UI objects. If model objects do not know about Java Swing objects (for example), then it is possible to unplug a Swing interface, or unplug a particular window, and plug in something else.

Thus, Model-View Separation supports Protected Variations with respect to a changing user interface.

To solve this design problem, the Observer pattern can be used.

Name:

Observer (Publish-Subscribe)

Problem:

Different kinds of subscriber objects are interested in the state changes or events of a publisher object, and want to react in their own unique way when the publisher generates an event. Moreover, the publisher wants to maintain low coupling to the subscribers. What to do?

Solution: (advice)

Define a "subscriber" or "listener" interface. Subscribers implement this interface. The publisher can dynamically register subscribers who are interested in an event and notify them when an event occurs.

An example solution is described in detail in Figure 26.22.

Figure 26.22. The Observer pattern.

[View full size image]

The major ideas and steps in this example:

  1. An interface is defined; in this case,

    PropertyListener with the operation

    onPropertyEvent .

  2. Define the window to implement the interface.

  3. When the

    SaleFrame1 window is initialized, pass it the

    Sale instance from which it is displaying the total.

  4. The

    SaleFrame1 window registers or

    subscribes to the

    Sale instance for notification of "property events," via the

    addPropertyListener message. That is, when a property (such as total) changes, the window wants to be notified.

  5. Note that the

    Sale does not know about

    SaleFrame1 objects; rather, it only knows about objects that implement the

    PropertyListener interface. This lowers the coupling of the

    Sale to the windowthe coupling is only to an interface, not to a GUI class.

  6. The

    Sale instance is thus a

    publisher of "property events." When the total changes, it iterates across all subscribing

    PropertyListeners , notifying each.

The

SaleFrame1 object is the observer/subscriber/listener. In Figure 26.23, it

subscribes to interest in property events of the

Sale , which is a

publisher of property events. The

Sale adds the object to its list of

PropertyListener subscribers. Note that the

Sale does not know about the

SaleFrame1 as a

SaleFrame1 object, but only as a

PropertyListener object; this lowers the coupling from the model up to the view layer.

Figure 26.23. The observer

SaleFrame1 subscribes to the publisher

Sale .

As illustrated in Figure 26.24, when the Sale total changes, it iterates across all its registered subscribers, and "publishes an event" by sending the

onPropertyEvent message to each.

Figure 26.24. The Sale publishes a property event to all its subscribers.

Applying UML: Note the approach to handing polymorphic messages in an interaction diagram, in Figure 26.24. The

onPropertyEvent message is polymorphic; the specific cases of polymorphic implementation will be shown in other diagrams, as in Figure 26.25.

Figure 26.25. The subscriber SaleFrame1 receives notification of a published event.

[View full size image]

SaleFrame1 , which implements the

PropertyListener interface, thus implements an

onPropertyEvent method. When the

SaleFrame1 receives the message, it sends a message to its

JTextField GUI widget object to refresh with the new sale total. See Figure 26.25.

In this pattern, there is still some coupling from the model object (the

Sale ) to the view object (the

SaleFrame1 ). But it is a loose coupling to an interface independent of the presentation layerthe

PropertyListener interface. And the design does not require any subscriber objects to actually be registered with the publisher (no objects have to be listening). That is, the list of registered

PropertyListeners in the

Sale can be empty. In summary, coupling to a generic interface of objects that do not need to be present, and which can be dynamically added (or removed), supports low coupling. Therefore, Protected Variations with respect to a changing user interface has been achieved through the use of an interface and polymorphism.

Why Is It Called Observer, Publish-Subscribe, or Delegation Event Model?

Originally, this idiom was called publish-subscribe, and it is still widely known by that name. One object "publishes events," such as the

Sale publishing the "property event" when the total changes. No object may be interested in this event, in which case, the

Sale has no registered subscribers. But objects that are interested, "subscribe" or register to interest in an event by asking the publishing to notify them. This was done with the

Sale.addPropertyListener message. When the event happens, the registered subscribers are notified by a message.

It has been called Observer because the listener or subscriber is observing the event; that term was popularized in Smalltalk in the early 1980s.

It has also been called the Delegation Event Model (in Java) because the publisher delegates handling of events to "listeners" (subscribers; see Figure 26.26).

Figure 26.26. Who is the observer, listener, subscriber, and publisher?

[View full size image]

Observer Is Not Only for Connecting UIs and Model Objects

The previous example illustrated connecting a non-UI object to a UI object with Observer. However, other uses are common.

The most prevalent use of this pattern is for GUI widget event handling, in both Java technologies (AWT and Swing) and in Microsoft's .NET. Each widget is a publisher of GUI-related events, and other objects can subscribe to interest in these. For example, a Swing

JButton publishes an "action event" when it is pressed. Another object will register with the button so that when it is pressed, the object is sent a message and can take some action.

As another example, Figure 26.27 illustrates an

AlarmClock, which is a publisher of alarm events and various subscribers. This example is illustrative in that it emphasizes that many classes can implement the

AlarmListener interface, many objects can simultaneously be registered listeners, and all can react to the "alarm event" in their own unique way.

Figure 26.27. Observer applied to alarm events, with different subscribers.

[View full size image]

One Publisher Can Have Many Subscribers for an Event

As suggested in Figure 26.27, one publisher instance could have from zero to many registered subscribers. For example, one instance of an

AlarmClock could have three registered

AlarmWindows , four

Beepers , and one

ReliabilityWatchDog . When an alarm event happens, all eight of these

AlarmListeners are notified via an

onAlarmEvent .

Implementation

Events

In both the Java and C# .NET implementations of Observer, an "event" is communicated via a regular message, such as

onPropertyEvent . Moreover, in both cases, the event is more formally defined as a class, and filled with appropriate event data. The event is then passed as a parameter in the event message.

For example:

class PropertyEvent extends Event

{

private Object sourceOfEvent;

private String propertyName;

private Object oldValue;

private Object newValue;

//...

}

//...

class Sale

{

private void publishPropertyEvent(

String name, Object old, Object new )

{

PropertyEvent evt =

new PropertyEvent( this, "sale.total", old, new);

for each AlarmListener al in alarmListeners

al.onPropertyEvent( evt );

}

//...

}

Java

When the JDK 1.0 was released in January 1996, it contained a weak publish-subscribe implementation based on a class and interface called

Observable and

Observer , respectively. This was essentially copied without improvement from an early 1980s approach to publish-subscribe implemented in Smalltalk.

Therefore, in late 1996, as part of the JDK 1.1 effort, the Observable-Observer design was effectively replaced by the more robust Java Delegation Event Model (DEM) version of publish-subscribe, although the original design was kept for backward-compatibility (but in general to be avoided).

The designs that have been described in this chapter are consistent with the DEM, but slightly simplified to emphasize the core ideas.

Summary

Observer provides a way to loosely couple objects in terms of communication. Publishers know about subscribers only through an interface, and subscribers can register (or de-register) dynamically with the publisher.

Related Patterns

Observer is based on Polymorphism, and provides Protected Variations in terms of protecting the publisher from knowing the specific class of object, and number of objects, that it communicates with when the publisher generates an event.