Thursday, September 3, 2009

Patterns - 019: Collectional patterns ( Iterator )


The Iterator pattern allows a client object to access the contents of a container in a sequential manner, without having any knowledge about the internal representation of its contents. The term container, used above, can simply be defined as a collection of data or objects.

To accomplish this, the Iterator pattern suggests that a Container object should be designed to provide a public interface in the form of an Iterator object for different client objects to access its contents. An Iterator object contains public methods to allow a client object to navigate through the list of objects within the container.

  • One of the simplest iterators available in Java is the java.sql.ResultSet class, which is usedto hold database records. This class offers a method next() for navigating along rows and a set of getter methods for column positioning.
  • In addition, the java.util.Vector class offers a method: public final synchronized Enumeration elements(). that returns an enumeration of elements or objects. The returned Enumeration object works as an iterator for the Vector object.
  • Besides the Enumeration interface, Java also offers the java.util.Iterator interface. concrete iterators can be built as implementers of the java.util.Iterator interface.

filtered iterators

  • An iterator object can return a selected set of objects (instead of all objects) in a sequential order. This filtering can be based on some form of input from the client. These types of iterators are referred to as filtered iterators.
Internal iterators
  • The collection itself offers methods to allow a client to visit different objects within the collection. For example, the java.util.ResultSet class contains the data and also offers methods such as next() to navigate through the item list.
  • There can be only one iterator on a collection at any given time.
  • The collection has to maintain or save the state of iteration.
External iterators
  • The iteration functionality is separated from the collection and kept inside a different object referred to as an iterator. Usually, the collection itself returns an appropriate iterator object to the client depending on the client input. For example, the java.util.Vector class has its iterator defined in the form of a separate object of type Enumeration. This object is returned to a client object in response to the elements() method call.
  • There can be multiple iterators on a given collection at any given time.
  • The overhead involved in storing the state of iteration is not associated with the collection. It lies with the exclusive Iterator object.
Eample : Internal iterators

Let us build an application to display data from a file Candidates.txt containing
details of different IT professionals who have offered their candidature
for a job opening. For simplicity, let us consider only three attributes — name,
current working location and certification type.

Let us define a container class AllCandidates :

  • Reads data from the data file as part of its constructor and stores the data in the form of a group of Candidate objects inside of an instance variable of Vector type.
  • Implements the built-in java.util.Iterator interface and provides implementation for its methods as follows:
  1. – hasNext() — Checks to see if there are any more candidates in the collection.
  2. – next() — Returns the next candidate object, if any, from the collection. If there is none, it throws a NoSuchElementException exception.
  3. – remove() — Because the application does not deal with the candidate data deletion, this method implementation does nothing.


The client does not have to be aware of how the data is stored, in which form and other details.

For the client, the AllCandidates object functions both as a container and an iterator. It makes use of the hasNext() and the next() methods to retrieve different Candidate objects and displays them in the user interface.




      import java.util.*;

      public class AllCandidates implements Iterator {
          private Vector data;
          Enumeration ec;
          Candidate nextCandidate;

          public AllCandidates() {
              initialize();
              ec = data.elements();
          }

          private void initialize() {
              /*
               Get data from db.
              */
              data = new Vector();
              FileUtil util = new FileUtil();

              Vector dataLines = util.fileToVector("Candidates.txt");
              for (int i = 0; i < dataLines.size(); i++) {
                  String str = (String) dataLines.elementAt(i);
                  StringTokenizer st = new StringTokenizer(str, ",");
                  data.add(
                          new Candidate(st.nextToken(), st.nextToken(),
                                  st.nextToken()));
              }
          }

          public boolean hasNext() {
              boolean matchFound = false;

              nextCandidate = null;

              while (ec.hasMoreElements()) {
                  Candidate tempObj = (Candidate) ec.nextElement();
                  nextCandidate = tempObj;
                  break;
              }
              return (nextCandidate != null);
          }

          public Object next() {
              if (nextCandidate == null) {
                  throw new NoSuchElementException();
              } else {
                  return nextCandidate;
              }
          }

          public void remove() {
          }

          ;

      }    

Eample : Filtered External iterators


Let us enhance the example application to allow a user to filter candidates by the type of certification they have. This enhancement can be designed usingan external filtered iterator.





When a user selects a certification type and clicks on the Retrieve button, the Search-Manager:

  • Creates an instance of the container AllCandidates. As part of its constructor, the AllCandidates object reads the data file and stores the data inside an instance variable data of type Vector. The client does not have to be aware of the data format or how the data is stored.
  • Invokes the getCertifiedCandidates(String type) method on the AllCandidates container object by passing the selected certification type as an argument. The getCertifiedCandidates() method creates an instance of the CertifiedCandidates class and returns it as an object of type java.util.Iterator.

Once the Iterator object is received, the client SearchManager makes use of the hasNext() and the next() methods to retrieve the matching Candidate objects and displays them in the user interface


CertifiedCandidates Class




import java.util.*;

public class CertifiedCandidates implements Iterator {
private Vector v;
AllCandidates ac;
String certificationType;
Candidate nextCandidate;
Enumeration ec;


public CertifiedCandidates(AllCandidates inp_ac,
                         String certType) {
  ac = inp_ac;
  certificationType = certType;
  ec = inp_ac.getAllCandidates();
}

public boolean hasNext() {
  boolean matchFound = false;
  while (ec.hasMoreElements()) {
      Candidate tempObj = (Candidate) ec.nextElement();
      if (tempObj.getCertificationType().equals(
              certificationType)) {
          matchFound = true;
          nextCandidate = tempObj;
          break;
      }
  }
  if (matchFound == true) {
  } else {
      nextCandidate = null;
  }
  return matchFound;
}

public Object next() {
  if (nextCandidate == null) {
      throw new NoSuchElementException();
  } else {
      return nextCandidate;
  }
}

public void remove() {
}

;

}      

AllCandidates Class : Modified




             import java.util.*;

             public class AllCandidates {
                 private Vector data;

                 public AllCandidates() {
                     initialize();
                 }

                 private void initialize() {
                     /*
                      Get data from db.
                     */
                     data = new Vector();
                     FileUtil util = new FileUtil();

                     Vector dataLines = util.fileToVector("Candidates.txt");
                     for (int i = 0; i <dataLines.size(); i++) {
                         String str = (String) dataLines.elementAt(i);
                         StringTokenizer st = new StringTokenizer(str, ",");
                         data.add(
                                 new one.nine.internal.Candidate(st.nextToken(), st.nextToken(),
                                         st.nextToken()));
                     }
                 }

                 public Enumeration getAllCandidates() {
                     return data.elements();
                 }

                 public Iterator getCertifiedCandidates(String type) {
                     return new CertifiedCandidates(this, type);
                 }

             }
         


No comments:

Post a Comment