BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Design Patterns
.NET 1.1+

Iterator Design Pattern

The iterator pattern is a design pattern that provides a means for the elements of an aggregate object to be accessed sequentially without knowledge of its structure. This allows traversing of lists, trees and other structures in a standard manner.

What is the Iterator Pattern?

The iterator pattern is a Gang of Four design pattern. This is a behavioural pattern as it defines a manner for controlling communication between classes or entities. The iterator pattern is used to provide a standard interface for traversing a collection of items in an aggregate object without the need to understand the underlying structure of that object. The interface provided is generally simplistic, providing methods to move to the next item, return to the beginning of the list, retrieve the current item and determine if the end of the list has been reached.

A variation upon the iterator design pattern is used extensively within C# and the .NET framework. Iterators are included in the standard array and collection classes and can easily be added to your own classes by implementing the IEnumerable and IEnumerator interfaces. C# version 2.0 also includes the yield keyword to simplify the process of creating iterators.

In most cases using the options provided by the C# language and the .NET framework is ideal when you wish to implement the iterator design pattern. In this article we will firstly implement a classic version of the pattern. We will then modify this to use the IEnumerator and IEnumerable interfaces and review the differences.

Implementing the Classic Iterator Pattern

Iterator Design Pattern UML

The UML class diagram above describes a classic implementation of the iterator design pattern. The items in the diagram are described below:

  • Client. Objects of this type are the consumers of the iterator design pattern. They request an iterator from an aggregate object when they wish to loop through the items that it holds. The methods of the iterator are then used to retrieve items from the aggregate in an appropriate sequence.
  • AggregateBase. This abstract class is the base class for aggregate objects. It includes a method that generates an iterator, which can be used to obtain references to the objects that subclasses contain. This class is often implemented as an interface.
  • ConcreteAggregate. The concrete aggregate classes provide the real functionality for aggregate objects that contain collections of items that can be traversed using an iterator.
  • IteratorBase. This abstract class is the base class for iterators. It defines a standard interface that includes methods to allow the elements of the aggregate that generated it to be looped through in sequence. This class is often implemented as a simple interface.
  • ConcreteIterator. Concrete iterators implement the interface defined by the IteratorBase class. They provide functionality specific to the ConcreteAggregate class used to generate them, hiding the implementation of the aggregate from the client.

The following shows the basic code of the iterator design pattern implemented using C#. In this case the aggregate's underlying objects are held in an ArrayList. This class is found in the System.Collections namespace so include the following using directive:

using System.Collections;

An indexer is used to allow read-only access to the items from the ArrayList from the iterator and a Count property allows the iterator to determine the size of the collection. This simplified code is useful for demonstrating the pattern but is unlikely to be required in a real solution as the ArrayList already provides iterator functionality through the IEnumerable interface.

public class Client
{
    public void UseIterator()
    {
        ConcreteAggregate aggr = new ConcreteAggregate();
        aggr.Add("One");
        aggr.Add("Two");
        aggr.Add("Three");
        aggr.Add("Four");
        aggr.Add("Five");

        IteratorBase iterator = aggr.CreateIterator();

        string item = (string)iterator.First();
        while (!iterator.IsDone())
        {
            Console.WriteLine(item);
            item = (string)iterator.Next();
        }
    }
}


public abstract class AggregateBase
{
    public abstract IteratorBase CreateIterator();
}


public class ConcreteAggregate : AggregateBase
{
    private ArrayList _items = new ArrayList();

    public override IteratorBase CreateIterator()
    {
        return new ConcreteIterator(this);
    }

    public object this[int index]
    {
        get { return _items[index]; }
    }

    public int Count
    {
        get { return _items.Count; }
    }

    public void Add(object o)
    {
        _items.Add(o);
    }
}


public abstract class IteratorBase
{
    public abstract object First();

    public abstract object Next();

    public abstract object CurrentItem();

    public abstract bool IsDone();
}


public class ConcreteIterator : IteratorBase
{
    private ConcreteAggregate _aggregate;
    int _position;

    public ConcreteIterator(ConcreteAggregate aggregate)
    {
        _aggregate = aggregate;
        _position = 0;
    }

    public override object First()
    {
        _position = 0;
        return CurrentItem();
    }

    public override object Next()
    {
        _position++;
        return CurrentItem();
    }

    public override object CurrentItem()
    {
        if (_position < _aggregate.Count)
            return _aggregate[_position];
        else
            return null;
    }

    public override bool IsDone()
    {
        return _position >= _aggregate.Count;
    }
}
26 July 2009