Pattern: Observer


Context

A change in one object (the subject) will sometimes require other objects (observers) to be updated. This relationship can be explicitly coded in the subject, but this requires knowledge about, how the observers should be updated. The result is that the objects become intertwined (termed closely coupled) and can't easily be reused.

Solution

Create a loosely-bound one-to-many relationship between an object and others that depend on it. A change in the object will result in the others receiving a notification, enabling them to update themselves accordingly.

There are two mechanisms which can be used to implement a loose coupling between a subject and its observers: Dependency and Events.

Dependency allows an observer object to register an interest in ALL aspects of another object. The observer then has to sort out what actually changed at runtime so it can do something sensible in response.

Events allow an observer to be interested in a specific aspect of a publisher and even request that a particular message is routed to them. Then, when the publisher triggers an event the routing and any message adaptation is automatic.

Clearly there is a trade off. Dependency is easy and fast to set up at initialization time and has a simple and fast mechanism underneath. The effort is at runtime, since the observer must do the event decoding and re-dispatching after the update is received.

The Event mechanism puts the onus on the programmer to route the messages at initialization time but the runtime is fast. The underlying mechanism is more complex and for many event registrations can generate a large number of objects.

The Dolphin MVP framework uses the Event mechanism, as these are easier to program and maintain.

Known Uses

The ListPresenter class triggers a #selection event whenever the selection changes.

onSelect
	"Handler for a selection change in the receiver's view"

	self trigger: #selection

Clients of a ListPresenter register an interest in the #selection event by sending #when: (with the parameter #selection) to the instance of ListSelectorModel. When the event is triggered, the client is sent a notification message.

ClassBrowserShell class>>createSchematicWiring
	"Private - Create the trigger wiring for the receiver"
	
	super createSchematicWiring.

	classesPresenter 
		when: #selection send: #classSelected to: self;
		when: #okToChangeSelection: send: #promptToSaveChanges: to: self.
	...
ClassBrowserShell>>classSelected
	"Private - The class selected within the receiver has changed. 
	Refresh the browser."

	| definition comment actualClass allCategory definitionView lastCategory |
	definition := String new asRichText.
	actualClass := self actualClass.

	actualClass isNil 
		ifTrue: [	
		...]

	self updatePackageSelection.
	definitionPresenter richtext: definition.
	commentPresenter value: comment.
	self updateCaption.

	self trigger: #class.