- Java provides a basic implementation of the Observer pattern
- class: java.util.Observable, the subject
- interface: java.util.Observer, implemented by the observer
- in Java, an "interface" is a list of abstract methods and constants
- a class that implements an interface is obliged to provide concrete definitions for the methods and constants of the interface it implements
- Observable source code, ported to ActionScript:
// PACKAGE
AsSetupPackage("org.moock.util");
// CLASS Observable
/**
* A Java-style Observable class used to represent the "subject"
* of the Observer design pattern. Views must implement the Observer
* interface, and register to observe the model via addObserver().
*/
org.moock.util.Observable = function () {
this.observers = new Array();
}
// PROPERTIES
// A flag indicating whether this object has changed.
org.moock.util.Observable.prototype.changed = false;
// A list of observers.
org.moock.util.Observable.prototype.observers = null;
// METHODS
/**
* Adds an observer for this object.
* @param o The observer to be added.
*/
org.moock.util.Observable.prototype.addObserver = function (o) {
// Can't add a null observer.
if (o == null) {
return false;
}
// Don't add an observer more than once.
for (var i = 0; i < this.observers.length; i++) {
if (this.observers[i] == o) {
// The observer is already observing, so quit.
return false;
}
}
// Put the observer into the list.
this.observers.push(o);
return true;
}
/**
* Removes an observer from this object.
*
* @param o The observer to remove.
*/
org.moock.util.Observable.prototype.deleteObserver = function (o) {
// Find and remove the observer.
var len = this.observers.length;
for (var i = 0; i < len; i++) {
if (this.observers[i] == o) {
this.observers.splice(i, 1);
return true;
}
}
return false;
}
/**
* Tell all observers that this object has changed.
*
* @param infoObj An object containing arbitrary data
* to pass to the observer.
*/
org.moock.util.Observable.prototype.notifyObservers = function (infoObj) {
// Use a null infoObject if none is supplied.
if (infoObj == undefined) {
infoObj = null;
}
// If the object hasn't changed, don't bother notifying observers.
if (!this.changed) {
return;
}
// Make a copy of the observers array. We do this
// so that we can be sure the list won't change while
// we're processing it.
var observersSnapshot = this.observers.slice(0);
// This change has been processed, unset the "changed" flag.
this.clearChanged();
// Invoke update() on all observers.
trace("Notifying observers: " + this.observers);
for (var i = observersSnapshot.length-1; i >= 0; i--) {
observersSnapshot[i].update(this, infoObj);
}
}
/**
* Removes all observers from this object.
*/
org.moock.util.Observable.prototype.deleteObservers = function () {
this.observers = new Array();
}
/**
* Indicates that this object has changed.
*/
org.moock.util.Observable.prototype.setChanged = function () {
this.changed = true;
}
/**
* Indicates that this object has either not changed or
* has notified its observers of the most recent change.
*/
org.moock.util.Observable.prototype.clearChanged = function () {
this.changed = false;
}
/**
* Checks if the object has changed.
*
* @return true if the object has changed, as determined by setChanged().
*/
org.moock.util.Observable.prototype.hasChanged = function () {
return this.changed;
}
/**
* Returns the number of observers for this object.
*
* @return An integer: the number of observers for this object.
*/
org.moock.util.Observable.prototype.countObservers = function () {
return this.observers.length;
}
- Flash MX ActionScript doesn't have "interfaces"
- we can simulate them manually with comments
- hence Observer "source code" is all comments:
/**
* interface org.moock.util.Observer
*
* This interface must be implemented by all observers of an
* Observable object.
*/
/**
* Observer.update(o, infoObj)
*
* Invoked automatically by an observed object when it changes.
*
* @param o The observed object (an instance of Observable).
* @param infoObj An arbitrary data object sent by
* the observed object.
*/