Iterator design pattern with C#

3 minute read

Iterator pattern is a design pattern which is used to traverse aggregate object often called container and access container’s object without exposing it’s underlying representation. Iterator pattern decoupled algorithm from aggregate object or container. In some cases, algorithms are container specific. We often use collection in C# and then we traverse the collection without knowing it’s internal details. Collection is grouping of some object. Objects can be same type or different type. Collection in fact actively used iterator pattern.

The above figure is UML class diagram for Iterator Pattern. The main idea behind the iterator pattern is to take the responsibility of traversing container and put it to the iterator object. The iterator object will maintain the state of the iteration, keeping track of the current item and track for the next item to iterate.

Benefits:

  • Access element of container without exposing it’s internal details.
  • Provides a uniform interface for traversing different collection (aggregate object).
  • Provides multiple simultaneous traversals in a collection.

Implementation:

Let’s come to the point. We are going to implement iterator design pattern. I am using here a collection for fruits item. The main actor in here:

  • IIterator – Interface to define Iterator (Concrete iterator class)
  • Iterator – Concrete iterator class which is used to iterate elements.
  • ICollection – Interface to define aggregate.
  • Collection – Concrete aggregate class.

I used FruitItem class as item class here.

Step 1: Create Item class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IteratorPattern
{
  /// Item class
  public class FruitItem
  {
    public string Id { get; set; }
    public string Name { get; set; }
  }
 
}

Step 2: Create IIterator Interface

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IteratorPattern
{
  /// Interface for Iterator
  public interface IIterator
  {
    FruitItem First();
    FruitItem Next();
    FruitItem CurrentItem { get; }
    bool IsDone { get; }
  }
}

Step 3: Create concrete Iterator class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IteratorPattern
{

    /// Concrete Iterator Class
    public class Iterator : IIterator
    {
        
        private Collection collection;
        private int current = 0;
        private int step = 1;
        
        public Iterator(Collection vCollection)
        {
            this.collection = vCollection;
        }
        
        public FruitItem First()
        {
            current = 0;
            return (FruitItem)collection[current];
        }
        
        public FruitItem Next()
        {
            current ++;
            
            if (!IsDone)
              return (FruitItem)collection[current];
            else
              return null;
        }
        
        public bool IsDone
        {
            get { return current >= collection.Count; }
        }
        
        public FruitItem CurrentItem
        {
            get { return (FruitItem) collection[current]; }
        }
        
        // Gets or sets stepsize
        public int Step
        {
            get { return step; }
            set { step = value; }
        }
    }
}

Step 4: Create collection interface.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IteratorPattern
{
  /// Interface for Aggregate class  
  public interface ICollection
  {
    Iterator CreateIterator();
  }
}

Step 5: Create concrete collection class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
 
namespace IteratorPattern
{
    ///
    /// Concrete aggregate class
    ///
    
    public class Collection : ICollection
    {
        private ArrayList lstFoodItem = new ArrayList();
        
        public Iterator CreateIterator()
        {
            return new Iterator(this);
        }
        
        // Get counted items
        public int Count
        {
            get
            {
                return lstFoodItem.Count;
            }
        }
        
        // Indexer
        public object this[int index]
        {
            get { return lstFoodItem[index]; }        
            set { lstFoodItem.Add(value); }
        }
    }
}

Step 6: Create client class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace IteratorPattern
{
class Program
{
    public static void Main(string[] args)
    {
        Collection collection = new Collection();
        
        collection[0] = new FruitItem() { Id = "1", Name = "Mango" };
        collection[1] = new FruitItem() { Id = "2", Name = "Orange" };
        collection[2] = new FruitItem() { Id = "3", Name = "Banana" };
        collection[3] = new FruitItem() { Id = "4", Name = "Apple" };
        collection[4] = new FruitItem() { Id = "5", Name = "Lichi" };
        collection[5] = new FruitItem() { Id = "7", Name = "Tamarind" };
        
        // Create iterator
        Iterator iterator = new Iterator(collection);
        Console.WriteLine("Items by iterating over collection");
        
        for (FruitItem item = iterator.First(); !iterator.IsDone; item = iterator.Next())
        {
            Console.WriteLine(item.Name);
        }
        
        Console.ReadLine();
    }
    }
}

Output:

Source code