Aug 17, 2013

Iterator Design Pattern

1 comment
Provide a way to access the elements of aggregate objects sequentially without exposing its representation. We can make the client independent on the movement of the cursors like forward traversal / backward traversal as well as the internal implementation of the list.

The actual implementation on how to traverse different types of collections will be different, yet the client code (calling code) should not be concerned about the details of the implementations. The iterator pattern helps to hide such details and provide a generic interface for the client to traverse different types of collections.

UML Class Diagram
  • The Iterator interface defines all the methods needed to traverse the collection.
  • The ConcreteIterator class implements the IIterator interface and has the actual implementations on how to traverse the collection.
  • The Aggregate interface defines the methods for the client. The methods that it defines allow the client code not to be bothered with the details on how the collection is traversed.
  • The ConcreteAggregate class implements the Aggregate interface and is the class that creates the ConcreteIterator. 
Nowadays any modern language supports this and so, we could use the foreach loop. In CSharp(C#), if we would like to have a class that will be a list you need to use the IEnumerator and IEnumerable interfaces and then it will support the foreach loop.

List should implement IEnumerable and the Iterator should implement IEnumerator.
Implementation 

Create Iterator class
public abstract class Iterator
{
    public abstract object First();
    public abstract object Next();
    public abstract object Previous();
}

Create Aggregate Class
public abstract class IList
{
    public abstract Iterator CreateIterator();
}

Create ConcreteAggregate class
public class ConcreteList : IList
{
    private ArrayList _items = new ArrayList();

    public int Count
    {
        get { return _items.Count; }
    }
        
    public object this[int index]
    {
        get { return _items[index]; }
        set { _items.Insert(index, value); }
    }

    public override Iterator CreateIterator()
    {
        return new ConcreteIterator(this);
    }
} 
 
Create ConcreteIterator class
public class ConcreteIterator : Iterator
{
    private int _currentIndex = 0;
    private ConcreteList _aggregate;

    public ConcreteIterator(ConcreteList aggregate)
    {
        _aggregate = aggregate;
    }

    public override object First()
    {
        if (_aggregate.Count == 0)
            return null;
        return _aggregate[0];
    }

    public override object Next()
    {
        object result = null;
        if (_currentIndex < _aggregate.Count - 1)
            result = _aggregate[++_currentIndex];

        return result;
    }

    public override object Previous()
    {
        object result = null;
        if (_currentIndex > 0)
            result = _aggregate[--_currentIndex];

        return result;
    }
}

Create a client to use above created iterator,
private void btnIterator_Click(object sender, EventArgs e)
{
    ConcreteList list = new ConcreteList();
    list[0] = "Item 1";
    list[1] = "Item 2";
    list[2] = "Item 3";
    list[3] = "Item 4";

    // Create Iterator and provide List
    ConcreteIterator iterator = new ConcreteIterator(list);
    Console.WriteLine("Iterating over collection: with iterator");

    object item = iterator.First();
    while (item != null)
    {
        Console.WriteLine(item);
        item = iterator.Next();
    }
}

Output
Iterating over collection: with iterator
Item 1
Item 2
Item 3
Item 4

1 comment :