Skip to main content

Design Patterns: Iterator Pattern

Free2015-03-07#Design_Pattern#迭代器模式#Iterator Pattern

The Iterator Pattern is a relatively simple pattern. Simply put, it uses an iterator to encapsulate traversal details. Most collection objects support traversal operations (such as Array, List, Set, Map, etc.), but since each collection object has different internal implementations, the interfaces called during traversal are also different. The iterator is designed to provide a unified interface for collection objects to support traversal operations.

no_mkd

I. What is the Iterator Pattern?

Use an iterator to encapsulate the traversal details of collection objects, allowing callers to traverse collections through a unified interface.

The iterator also provides certain protection for collection objects. To traverse a collection, just call the iterator's methods. We don't need to know (and don't have to know) the internal data management method of the collection.

II. An Example

Suppose there is a set of custom objects, and we don't know what collection object is used to maintain them. It could be Array, List, or something else. Our job is to traverse this set of objects (or add some extra processing based on the traversal). Think about how we can implement this?

First, determine the type of the collection object, then handle each differently. For each different collection type, we need a different loop to handle it. Although these loop blocks have only subtle differences, we still have to provide a loop to handle them... If there are 100 different collection types, we may have to use 100 similar loops to implement traversal, undoubtedly resulting in a large amount of redundant code. So we need a unified entry point, hoping to turn n loops into one highly adaptable loop. The iterator is the unified entry point we've been longing for:

Iterator Interface

package IteratorPattern;

/**

  • @author ayqy

  • Define iterator */ public interface Iterator {

    /**

    • @return Whether there is a next element in the collection / public abstract boolean hasNext(); /*
    • @return Return the next element in the collection */ public abstract Object next(); }

We also need to implement some concrete iterators to implement traversal details:

Array Iterator:

package IteratorPattern;

/**

  • @author ayqy

  • Implement array iterator */ public class ArrayIterator implements Iterator{ MyObject[] arr;//Custom object array int index = 0;//Current index

    public ArrayIterator(MyObject[] arr){ this.arr = arr; }

    @Override public boolean hasNext() { if(index < arr.length && arr[index] != null) return true;

     return false;
    

    }

    @Override public Object next() { MyObject mo = arr[index]; index++;

     return mo;
    

    } }

P.S. Note the concrete implementation of the hasNext method in the Array iterator

List Iterator:

package IteratorPattern;

import java.util.List;

/**

  • @author ayqy

  • Implement List iterator */ public class ListIterator implements Iterator{ List<MyObject> list;//Collection object int index = 0;//Current index

    public ListIterator(List<MyObject> list){ this.list = list; }

    @Override public boolean hasNext() { if(index < list.size()) return true;

     return false;
    

    }

    @Override public Object next() { MyObject mo = list.get(index); index++;

     return mo;
    

    } }

With these concrete iterators, we only need one loop to get it done:

/**
 * Print all content of the collection
 * @param iter Iterator of the collection
 */
private static void printObjs(Iterator iter){
	while(iter.hasNext()){
		System.out.println(iter.next().toString());
	}
}

III. Java's Support for Iterator

Due to the convenience and necessity of iterators, Java provided support for Iterator after version 1.5. Currently, many collection objects support Iterator, such as Set, List, Map, SortedSet, SortedMap, HashSet, TreeSet, ArrayList, LinkedList, Vector, etc.

The only thing that doesn't support iterators might be arrays (except for special ones like stacks and queues). Above we implemented a custom Iterator interface. Actually, Java itself provides this interface (java.util.Iterator), but the difference is:

The Java.util.Iterator interface defines three methods (in addition to hasNext and next methods, there's also a remove method):

If a collection object is unwilling to provide a remove method, it doesn't matter. We can throw an exception to refuse implementation, like this:

package IteratorPattern;

/**

  • @author ayqy

  • Implement array iterator using Java's provided Iterator interface */ public class JavaArrayIterator implements java.util.Iterator{ MyObject[] arr;//Custom object array int index = 0;//Current index

    public JavaArrayIterator(MyObject[] arr){ this.arr = arr; }

    @Override public boolean hasNext() { if(index < arr.length && arr[index] != null) return true;

     return false;
    

    }

    @Override public Object next() { MyObject mo = arr[index]; index++;

     return mo;
    

    }

    @Override public void remove() { //Throw operation not supported exception throw new UnsupportedOperationException(); } }

The iterator calling method remains completely unchanged:

/**
 * Print all content of the collection
 * @param iter Iterator of the collection
 */
private static void printObjs(java.util.Iterator iter){
	while(iter.hasNext()){
		System.out.println(iter.next().toString());
	}
}

IV. Implicit Calling of Iterators

Many languages support for each (or for in) loops, whose internal implementation calls the iterator to complete traversal. Of course, this is just a small piece of common knowledge. More importantly, learn the design principles of iterators and define your own iterators when needed.

V. Extension

The Iterator Pattern itself is relatively simple. We may not even need to define our own iterators anymore (the iterator interfaces provided by APIs can almost meet our needs).

But when iterators are combined with the Composite Pattern, they can do something incredible (will be introduced in detail in the Composite Pattern, click me to jump>>)

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment