Recitation 11 November 11, 2011
Today’s Goals: Automatic refresh Learn and apply the Observer pattern
Fixing the Refresh Problem Tell Object Editor when changes have occurred Observer pattern: “Observable” Object Obervers / Listeners Events / Notifications
Analogy: AlertCarolina You register / listen for alerts When the state changes, you receive a notification indicating: State has changed Information relevant to the change
Two Steps in Observer Pattern 1) Observers register with observable objects to listen for events (one time only) 2) When observable object undergoes an appropriate change, it sends an informative notification to all registered observers
Step 1: Registration (Properties) Observable class must implement: public void addPropertyChangeListener( PropertyChangeListener listener) This method adds the provided listener to a collection of listeners (as long as the collection doesn’t already contain this listener – avoid double notifications) If ObjectEditor.edit() is called on a class that implements this method, ObjectEditor will automatically register itself for notifications from this class
Step 2: Notification (Properties) When the observed object changes state, it calls propertyChange( PropertyChangeEvent event) on each of its observers Construct a PropertyChangeEvent with: this (i.e. a pointer to the observed object) The name of the changed property as a String “width”, “x”, “knight”, etc. The old value of the property The new value of the property
Step 2 Example: setWidth(int newWidth) int oldWidth = width; width = newWidth; PropertyChangeEvent event = new PropertyChangeEvent(this, “width”, oldWidth, newWidth); /* call propertyChange(event) on all observers */
Collection Observers Very similar to property observers Must implement public void addVectorListener(VectorListener listener); When collection changes, call on all registered listeners: updateVector(VectorChangeEvent event)
Vector Change Event package util.models; public class VectorChangeEvent { // constants to be used for event type public static final int AddComponentEvent = 1, DeleteComponentEvent = 2, ChangeComponentEvent = 3, InsertComponentEvent = 4, CompletedComponentsEvent = 5, ClearEvent = 6, UndefEvent = 1000; // constructor, oldObject can be null when no value is replaced public VectorChangeEvent(Object theSource, int type, int posn, Object oldObject, Object newObject, int newSize) { … } … }
Vector Change Event To create a VectorChangeEvent within an Observer, pass the following into the VectorChangeEvent constructor (in order): this The int corresponding to the change that occurred, e.g. VectorChangeEvent.AddComponentEvent The index of the affected element The Object that was previously at that location (null for push()) The Object that is now at that location (null for pop()) The new size of the collection
Recitation Specification Download Recitation11.zip from the Recitations page Implement ObservableAlignedShapeStack: Create an ArrayList instance variable that stores all objects listening to / observing this stack (VectorChangeListener objects) public void addVectorListener(VectorListener listener) /* adds the provided listener to the list of listeners, but only if the listener is not already in the list */ Hint: Use the add() and contains() methods from ArrayList Create: void notifyAllListeners(VectorChangeEvent event) For each listener in the ArrayList, call propertyChange on that listener with the provided event Override push() and pop() so that they notify all listeners of the change made to the collection (but only IF a change was made!) If done correctly, you won’t need to manually refresh