Factor out common code and make your Iterators observable On this month’s tip we will take a brief look at the Iterator and Observer design patterns and then go on to examine how to use these patterns together to create Iterator Observers. Readers familiar with these two patterns may want to move straight to the section called Iterator Observers.IteratorsIterators provide an abstract mechanism to access elements in collection classes without revealing their underlying representations. A collection class is a class that can contain a number of items in a certain data structure such as linked lists and hash tables. An example of a collection class is java.util.Vector.The first two listings explore why hiding the underlying representation of a collection class helps reduce the level of coupling between classes. The following enumeration is an example of an iterator in Java: public interface java.util.Enumeration { public abstract boolean hasMoreElements(); public abstract Object nextElement(); } If used correctly, Iterators promote loose coupling between collection classes and their clients. Listing 1 illustrates a poor use of an Iterator.public class Display extends Panel { private List itemList= new List(); public Display() { add( itemList ); } public void InitList( Vector opts ) { Enumeration e=opts.elements(); while( e.hasMoreElements() ) { String item=(String)e.nextElement(); itemList.addItem( item ); } } } Listing 1: A poor use of an IteratorSo why have I said that the approach used in Listing 1 is poor? InitList() is coupled to the use of a Vector. Consider the impact and effort involved if your system contains many dependencies on a particular collection class — in this case Vector — and you later need to change it to your own class or a third-party class that suits your system better. So how can we improve this design? Listing 2 shows how, by using polymorphism and passing an iterator as a parameter rather than a Vector, class Display can be used by any client with a collection class that supports the Enumeration interface. Class Test demonstrates this by passing either a Vector or a hashtable’s Enumeration to the Display object. (For more information on abstraction and polymorphism, see my JavaWorld article, “Polymorphism and Java.”) public class Display extends Panel { //as listing 1 public void InitList( Enumeration e ) { while( e.hasMoreElements() ) { String item=(String)e.nextElement(); itemList.addItem( item ); } } } public class Test { private Vector v = new Vector(); private Hashtable ht = new Hashtable(); private Display disp = new Display(); public void WithVector() { disp.InitList( v.elements() ); } public void WithHashTable() { disp.InitList( ht.elements() ); } } Listing 2: Improved usage of IteratorThose readers who are interested in experimenting with Iterators should write a class that can read a row at a time from a text file, or even better from a database table, and provides an iterator over the rows in the form of the java.util.Enumeration interface. An example using JDBC occurs later in this article.ObserversExamples of the Observer pattern can be found in Smalltalk’s MVC (Model View Controller), Microsoft’s C++ MFC document/view architecture, and Java’s own Observer and Observable interfaces. The Observer pattern generally is used to inform clients (Observers) if the state of an object (known as the subject) that they have expressed an interest in changes. Consider the code in Listing 3 (which does not use the Observer pattern), where a Spreadsheet and a Graph object display different representations of the same data. When the data changes, these objects must be notified so they can update their displays. What would be the impact of adding extra views to the App class? And how you could enable/disable the views being updated?public class Spreadsheet {...} public class Graph {...} public class Data {...} public class App extends Applet { private Data data = new Data(); //views private Graph graph = new Graph(); private Spreadsheet ssheet = new Spreadsheet(); //other views private void UpdateViews() { //Method called if the user has changed something graph.update( data ); sheet.update( data ); //other interested parties } } Listing 3: Example without the ObserverFortunately the Observer pattern comes to the rescue! The Observer pattern decouples the concrete observers from the subject. Listing 4 shows a simple example of how the Observer pattern improves the design in Listing 3. Observer and Observable are part of the java.util package. public class Spreadsheet implements java.util.Observer { //impl public void update(Observable o, Object arg) { //update the spreadsheet with the changed data } } public class Graph implements Observer {...} pubic class Data Extends java.util.Observable { //inherits all the methods to add/remove and notify //observers from Observerable public void ChangeData() { //change the data then... setChanged(); // inherited protected method // notifyObservers() will invoke update() on all registered observers notifyObservers(this); //inherited method } } public class App extends Applet { private Data data = new Data(); //views private Graph graph = new Graph(); private Spreadsheet ssheet = new Spreadsheet(); //other views... public class App() { //register the observers with the observable data.addObserver( graph ) data..addObserver( ssheet ) //add other types } private void UpdateViews() { //Method called if the user has changed something //update the data object data. ChangeData(); } } Listing 4: Example with an ObserverSo how do the Spreadsheet and Graph objects in Listing 4 get updated? Basically, the Observer pattern implements a kind of callback from the Observable object to the Observer; take a closer look at the method Data.ChangeData() in Listing 4.With a brief tour of Observers and Iterators under our belts, let’s quickly recap and then go on to examine how we can use the two patterns together. Summary of iterator and observer design patternsHere are the basic definitions of the two terms:Iterator: An abstract mechanism for accessing the elements in a collection.Observer: The Observer pattern has two participants, Observers and Observables and defines a one to many relationship between them. An Observerable object contains a list of its Observers. When the Observable’s state changes it notifies its Observers so that they are updated automatically.For more information on design patterns, including Iterator and Observer, see “Design Patterns” Gamma et al, Addison Wesley. (See the Resources section for a link to this site.)Iterator observerIterator client code takes the form of Listing 5, where the client is responsible for writing the loop, getting the contents, and processing them. while( enumeration.hasMoreElements() ) { //1. get element //2. process } Listing 5: Generic iterator client codeIn systems that use Iterators extensively, it is quite common to find many occurrences of the generic client code; frequently these iterators are abstractions over database query results or products of CORBA server objects in multitier architectures.The goal of the Iterator Observer is to factor out the common client code and place it in the iterator itself. If you examine the code in Listing 5, you will find that the generic code is 1) the while loop, and 2) getting the element at the current position, whereas the client specific code is the processing of that element. Listing 6 introduces the ObservableEnumeration class, which acts as an observable iterator and delegates to an Enumeration instance.public class ObservableEnumeration extends java.util.Observable { private Enumeration iter; public ObservableEnumeration( Enumeration e) { iter=e; } public void Iterate() { int num_observers=countObservers(); if(num_observers>0) { while(iter.hasMoreElements()) { setChanged(); notifyObservers( iter.nextElement() ); } } else { //throw an exception //method called without registering //any observers } } public void Iterate(Observer [] observers ) { int num=observers.length; while(iter.hasMoreElements()) { for( int I=0;I<num;I++) observers[I].update( this, iter.nextElement() ); } } public void Iterate(Observer observer ) { Observer [] obs = new Observer[1]; obs[0] = observer; Iterate( obs ); } } Listing 6: Example of observable IteratorClass ObservableEnumeration has three overloaded methods called Iterate: Iterate(): Used if the client has registered Observers.Iterate(Observer observer): Allows clients to pass an Observer instance without the overhead of registering/deregistering.Iterate(Observer [] observers): Allows clients to pass an array of Observers without the overhead of registering/deregistering themselves.ObserverableEnumeration offers a flexible extension to the Enumeration class. Listing 7 shows an example of client code using this class. See how simple it is to write a client of the ObserverableEnumeration? The actual iteration is removed from the client.public class NewDisplay extends Panel implements java.util.Observer { private Choice items = new Choice(); //ctor and init code //Observer impl public void update( Observable observerable, Object arg ) { items.addItem( (String)arg ); } } public class Test2 { private Vector v = new Vector(); private Hashtable ht = new Hashtable(); private NewDisplay disp = new NewDisplay(); private void Setup(Enumeration e) { ObservableEnumeration oe = new ObservableEnumeration( e ); oe.Iterate( disp ); } public void WithVector() { Setup( v.elements() ); } public void WithHashTable() { Setup( ht.elements() ); } } Listing 7: Using the Observable IteratorAlthough the example in Listing 7 is quite simple, it demonstrates how the Observable Iterator can be used. Listing 8 looks at a more realistic example in which the class QueryExecuter is an abstraction hiding the underlying persistent storage — in this case a relational database through JDBC. public class QueryExecuter extends Observerable { private String currentOp="none"; private ResultSet resultSet; private Connection dbConnection; public QueryExecuter() { //impl to attach to source //assign dbConnection } public boolean GetEmployees() { currentOp="employee"; Statement stmt = dbConnection.createStatement(); String sql = "select * from EMPLOYEE"; //execute query and cache the results resultSet = stmt.executeQuery(sql); return resultsSet.next(); } //other Gets public void Iterate(Observer observer) { //iterate stored results //make the appropriate object if(currentOP.equals("employee") ) { do { //make an Employee object Employee emp= new Employee(); //assign attributes from resultsSet; observer.Update(this,emp); } while( resultSet.next() ); } } public Iterate(Observer [] observers ) { //impl } } public class EmployeeDisplay extends Panel implements Observer { private List empList = new List(); //ctor etc //Observer impl public void update( Observable observerable, Object arg ) { Employee emp=(Employee)arg; empList.addItem( emp.GetName() ); } } public class Test3 { private QueryExecuter executer= new QueryExecuter(); private EmployeeDisplay disp = new EmployeeDisplay(); public void TestGetEmployees() { if( executer.GetEmployees()) { executer.Iterate( disp ); } } } Listing 8: The Observable Iterator in action with JDBCAlthough it is not used in the example in Listing 8, QueryExecuter extends Observable. This gives clients the option of registering Observers rather than passing them as parameters. The method Test3.TestGetEmployees() first invokes the GetEmployees() method. If this method returns true, the query has succeeded and Test3.TestGetEmployees() proceeds by invoking the QueryExecuter.Iterate() and passing the EmployeeDisplay object as a parameter. (Remember: EmployeeDisplay implements Observer.) To make the example in Listing 8 easier to understand, I have used String currentOp to store the last query type. (For a better way of doing this, see my JavaWorld article on “Typesafe Constants.”) This allows the Iterate() method to make the appropriate concrete object to pass to its Observers.Those readers interested in hiding the nature of their systems’ persistent storage should try to design a generic interface for the QueryExecuter that doesn’t require explicit method names such as GetEmployees(). Another point to note here is that by encapsulating your queries in a class like QueryExecuter, a more scalable design results. Just consider the impact on your system’s design if you later have to replace your RDBMS with a ODBMS and you have designed your system to pass SQL statements and JDBC ResultSet objects around! ConclusionAs with all idioms and patterns, it is important to use them to solve a problem — not to introduce complexity. Below I have listed the occasions when the Iterator Observer idiom can be extremely effective.When more than one object is updated by the elements retrieved from an Iterator.When the same iterator client code is duplicated throughout a system.When encapsulating different Iterator syntax in adaptors that provide an Iterate() method.When encapsulating access to queries on persistent data or from remote objects.Philip Bishop is technical director and a consultant at Eveque Systems Ltd in the U.K, which specializes in designing and implementing distributed object systems using Java, CORBA, C++, and ODBMS.