Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 1 of 1

Thread: How to Use an Observer Pattern

  1. #1
    Administrator copeg's Avatar
    Join Date
    Oct 2009
    Location
    US
    Posts
    5,320
    Thanks
    181
    Thanked 833 Times in 772 Posts
    Blog Entries
    5

    Default How to Use an Observer Pattern

    The observer design pattern is a popular, powerful, and beautiful way to facilitate communication between two or more java objects, allowing one object to notify 'listeners' of changes with itself, and doing so in a way that results in a very loose dependency between the two objects. Objects responsible for notifying observers can have little idea of the state of who they are notifying, only relying on abstract functions defined through an interface. This provides a powerful way to write classes that are relatively independent from other portions of code, making them re-usable as well as facilitating changes to code without breaking dependencies.

    To demonstrate this pattern, let us first start with a problem. Suppose we have some data, defined within a particular Class we'll call DataModel (see below). How can we be notified when the underlying data with this class has changed?

    To tackle this problem, lets first define what we want our observers to be notified of. All we want is to be notified of changes to the data, so we'll define an interface containing a single function: dataChanged()

    /**
     * Listener interface which defines changes to an underlying data model. 
     *
     */
    public interface DataListener{
     
    	/**
    	 * Called when data has changed. 
    	 * @param dataObject The object that has changed
    	 */
    	public void dataChanged(Object dataObject);
     
    }

    Simple enough. From the perspective of the classes that implement this interface, dataChanged() will be called when the data has changed, and the object whose data has changed will be passed as the parameter.

    Now, who will ultimately invoke this method? Lets define our DataModel class, the class who we want to Observe:

    /**
     * A data class which acts as a wrapper to a String. 
     *
     */
    public class DataModel{
     
    	private String data;
    	/**
    	 * Creates a new DataModel.
    	 * @param data
    	 */
    	public DataModel(String data){
    		super();
    		setData(data);
    	}
    	/**
    	 * Sets the data of this model. 
    	 * @param newData
    	 */
    	public void setData(String newData){
    		this.data = newData;
    	}
    }

    The above code outlines an extremely simple class, pretty much for demonstration only, with a single variable called data. How can we notify other objects when this data value has changed? Together with the interface described above, we can make a few changes to DataModel which a) store references to observers and b) call the functions of those observers when the data has changed:

    /**
     * A data class which acts as a wrapper to a String, and implements the Observer
     * design pattern to notify listeners of changes to the underlying model.
     *
     */
    public class DataModel{
     
    	private String data;
     
    	private List<DataListener> listeners = new ArrayList<DataListener>();
    	/**
    	 * Creates a new DataModel.
    	 * @param data
    	 */
    	public DataModel(String data){
    		super();
    		setData(data);
    	}
     
    	/**
    	 * Removes the parameter listener. 
    	 * @param listener
    	 */
    	public void removeListener(DataListener listener){
    		listeners.remove(listener);
    	}
    	/**
    	 * Adds the parameter listener. 
    	 * @param listener
    	 */
    	public void addListener(DataListener listener){
    		listeners.add(listener);
    	}
    	/**
    	 * Sets the data of this model. 
    	 * @param newData
    	 */
    	public void setData(String newData){
    		this.data = newData;
    		for ( int i = 0; i < listeners.size(); i++ ){
    			listeners.get(i).dataChanged(this);
    		}
    	}
    }

    While we could have stored a reference to a single Observer, the use of a List to store references to multiple Observers allows one to notify several objects of a change in data.

    Now, lets test this puppy out:

    	public static void main(String[] args){
    		//create our model
    		DataModel ourModel = new DataModel("Testing");
    		//create an anonymous class that implements DataListener
    		DataListener listener = new DataListener(){
    			public void dataChanged(Object o){
    				System.out.println("This is a test");
    			}
    		};
    		ourModel.addListener(listener);
    		ourModel.setData("Testing 2");
    	}

    The above snippet first creates a DataModel, then add a Listener which simply prints out a line to the console update changes to the model. Finally, it adds the listener and changes the model. Output:

    This is a test

    Yes, a very simple example, but demonstrates how this design pattern can be implemented as well as the loosely coupled interaction between the Model and Observer - we can remove listeners at any time, register more listeners, and lastly easily change the Observers - what they are and what they do - without our DataModel class caring in the least (so long as they still implement the correct interface).

    It should be noted that while the above is a custom implementation, the java.util library provides classes to accomplish the same task in the form of the Observable and the Observer.

    While the example above is (hopefully) too simple to serve any real purpose other than demonstration, the same pattern can be applied to a wide range of more complex scenarios. A simple case: how about notifying observers when a Thread has finished? (for those that know little about threads I suggest reading Lesson: Concurrency for more information).

    Our Observer
    /**
     * A interface that can be used by the NotificationThread class to notify an
     * object that a thread has completed. 
     * 
     */
    public interface ThreadListener {
    	/**
    	 * Notifies this object that the Runnable object has completed its work. 
    	 * @param runner The runnable interface whose work has finished.
    	 */
    	public void notifyOfCompletion( Runnable runner );
    }
     
    /**
     * An abstract class implementing the Runnable interface that can be used to notify listeners
     * when the runnable thread has completed. To use this class, first extend it and implement
     * the doRun function - the doRun function is where all work should be performed. Register any listeners that 
     * want to be notified, Then create a new thread with this as its Runnable. 
     *
     */
     
    public abstract class NotificationRunnable implements Runnable{
     
    	/**
    	 * An abstract function that children must implement. This function is where 
    	 * all work - typically placed in the run of runnable - should be placed. 
    	 */
    	public abstract void doRun();
     
    	/**
    	 * Our list of listeners to be notified upon thread completion.
    	 */
    	private java.util.List<ThreadListener> listeners = Collections.synchronizedList( new ArrayList<ThreadListener>() );
     
    	/**
    	 * Adds a listener to this object. 
    	 * @param listener Adds a new listener to this object. 
    	 */
    	public void addListener( ThreadListener listener ){
    		listeners.add(listener);
    	}
    	/**
    	 * Removes a particular listener from this object, or does nothing if the listener
    	 * is not registered. 
    	 * @param listener The listener to remove. 
    	 */
    	public void removeListener( ThreadListener listener ){
    		listeners.remove(listener);
    	}
    	/**
    	 * Notifies all listeners that the thread has completed.
    	 */
    	private final void notifyListeners() {
    		synchronized ( listeners ){
    			for (ThreadListener listener : listeners) {
    			  listener.notifyOfCompletion(this);
    			}
    		}
    	}
    	/**
    	 * Implementation of the Runnable interface. This function first calls doRun(), then
    	 * notifies all listeners of completion.
    	 */
    	public void run(){
    		try{
    			doRun();
    		}finally{
    			notifyListeners();
    		}
    	}
    }

    The above code allows one to create long running tasks in a Thread, and notify observers when the task is complete: useful in many contexts, for example updating a user interface when the task is complete (note how NotificationRunnable is completely independent of any user interface implementation).

    With these two examples, its easy to see how this pattern can be applied in many contexts. Its also easy to see how this pattern completely decouples one object - designed for one purpose - from another object (designed for another purpose), which makes the code re-usable and readily changed. There exist uses all over the place, from notifying a GUI when a data model has changed to listening for changes in a Collection (List, Set, etc…)...and many, many more.
    Last edited by copeg; February 9th, 2011 at 10:28 PM.


Similar Threads

  1. to print pattern
    By Charanleen in forum What's Wrong With My Code?
    Replies: 9
    Last Post: October 3rd, 2010, 07:54 AM
  2. Observer
    By JustMe in forum What's Wrong With My Code?
    Replies: 0
    Last Post: October 1st, 2010, 08:48 PM
  3. a new pattern with a new architecture
    By mcgrow in forum Web Frameworks
    Replies: 0
    Last Post: August 4th, 2010, 02:28 PM
  4. [SOLVED] Need Regex for a pattern
    By mallikarjun_sg in forum Java Theory & Questions
    Replies: 7
    Last Post: May 5th, 2010, 02:06 AM
  5. url pattern issue - please help me...
    By bharathik in forum JavaServer Pages: JSP & JSTL
    Replies: 2
    Last Post: November 9th, 2009, 04:28 AM