Extended Observer-Pattern

The following post discusses an "extended" version of the Observer-Pattern.

The intent of the observer pattern is often described as an one-to-many dependency.
The key fact is that when one object changes its state, all listeners are notified about that change [GHJV95].

There are only two relevant kinds of objects in this pattern, observers and an observable.

An observable is basically an object that holds information on which other objects (observer) could be interested in.
When the data-state of the observable has changed the observers are notified about the change.
This kind of interaction is called publish-subscribe. The observable is the publisher of notifications. It sends out these notifications without having to know who its observers are[GHJV95].

So good so far...

Now let's examine the concrete implementation of an extended scenario.
extended observer pattern

The extended part in this observer pattern is the ISpecificObserver interface. If only specific notifications are interesting for an observer, it has to implement the ISpecificObserver interface and return an Array of notification interests (acceptedNotifications():Array).

Here are the interesting parts of the Observable:

public function addObserver( o: IObserver ): void
{
	if( o is ISpecificObserver )
	{
		var notifications: Array = ISpecificObserver( o ).acceptedNotifications();
		var len: int = notifications.length;
		var list: ISet;
 
		while( --len > -1 )
		{
			list = _specificObservers.getValue( notifications[ len ] );
 
			if( list == null )
			{
				list = new ArraySet();
 
				_specificObservers.put( notifications[ len ], list );
			}
 
			list.add( o );
		}
	}
	else if( o is IObserver )
	{
		_observers.add( o );
	}
}
public function notifyObservers( type: String = null, data: * = null ): void
{
	var node: LinkedNode;
 
	if( type != null )
	{
		var list: LinkedSet = LinkedSet( _specificObservers.getValue( type ) );
 
		if( list != null )
		{
			// -- notify all ISpecificObserver
			node = list.firstNode;
 
			while( ( node = node.post ) != null )
			{
				ISpecificObserver( node.value ).update( this, type, data );
			}
		}
	}
	else
	{
		type = DataNotificationType.GENERIC;
	}
 
	// -- notify all IObserver
	node = _observers.firstNode;
 
	while( ( node = node.post ) != null )
	{
		IObserver( node.value ).update( this, type, data );
	}
}

An concrete implementation could look like this:

package
{
	import com.addicted2flash.data.DataNotificationType;
	import com.addicted2flash.util.IObservable;
	import com.addicted2flash.util.ISpecificObserver;		
 
	/**
	 * @author Tim Richter
	 */
	public class ObserverExample implements ISpecificObserver
	{
		public function ObserverExample()
		{
		}
 
		public function acceptedNotifications(): Array
		{
			return [ DataNotificationType.COMPLETE ];
		}
 
		public function update( observable: IObservable, type: String, data: * ): void
		{
			switch( type )
			{
				case DataNotificationType.COMPLETE:
					// -- do something!
					break;
			}
		}
	}
}

References:

[GHJV95] E. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Patterns – Elements of Reusable Object-Oriented Software, Addison-Wesley, 1995

One Response (Add Your Comment)

Trackbacks:

Leave a Reply

Formatting: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>