Categories: Design Pattern

Behavioral Patterns – Iterator

Iterator – It let the programs traverse all of the collection elements without their underlying representation and can non-know the set objects base layer to describe it.

From Design Pattern – Behavioral Patterns

Structure

Iterator pattern – Class diagram UML

Applicability

It lets the program travers elements of a collection without exposing its underlying representation, such as list, stack, tree, etc.

  • Use the iterator pattern when the program collection has a complex data structure under the hood, but the developers want to hide its complexity from the clients for convenience or security reasons.
  • Use the iterator pattern to reduce duplication of the traversal code across the projects. Its pattern can improve the project code to be more lean and clean. It means the non-trivial iteration algorithms code tends to be rich bulky, which may blur the original responsibility code and make it less maintainable when placed here within the business logic of the program(Business Logic Layer – BLL).
  • Use the iterator pattern when the program wants to traverse different data structures or when these structure types are unknown beforehand, which means these patterns provide a couple of generic interfaces for both the collections and iterators. Suppose the programs use these interface, it will still work if the programs pass it various collection methods and iterators which implements these interfaces.

Pros and Cons

PROS

  • Single responsibility principle: The programs can clean up the client code and the collections by extracting bulky traversal algorithms into separate classes.
  • Open-closed principle: The program can implement new types of collections iterators, and pass them to existing code without breaking anything.
  • The program can iterate over the same collection in parallel because each iterator object contains its iteration state. It also can delay an iteration and continue it when needed for the same reason.

CONS

  • Using the pattern is going to be overkill if the program only works with the same collections.
  • Use an iterator pattern which may be less efficient than going through elements of some specialized collection directly.

How to Implement

This pattern article will provide two basic sample codes, such as the abstract class’s iterator pattern and the interface class’s iterator pattern. The abstract class and the interface class have a few parts working differently based on the object class characteristic factor in the .NET framework. If the developers don’t know the abstract class mechanism, the author will provide you with advice on choosing the interface class mechanism.

#1 Basic Sample

Abstract class sample

static void Main(string[] args)
{
 var collection = new WordsCollection();
 collection.AddItem("First");
 collection.AddItem("Second");
 collection.AddItem("Third");

 Console.WriteLine("Straight traversal:");

 foreach (var element in collection)
 {
  Console.WriteLine(element);
 }

 Console.WriteLine("\nReverse traversal:");

 collection.ReverseDirection();

 foreach (var element in collection)
 {
  Console.WriteLine(element);
     }

 Console.ReadKey();
}

abstract class Iterator : IEnumerator
{
 object IEnumerator.Current => Current();

 public abstract int Key();

 public abstract object Current();

 public abstract bool MoveNext();

 public abstract void Reset();
}

abstract class IteratorAggregate : IEnumerable
{
 public abstract IEnumerator GetEnumerator();
}

class AlphabeticalOrderIterator : Iterator
{
 private WordsCollection _collection;

 private int _position = -1;

 private bool _reverse = false;

 public AlphabeticalOrderIterator(WordsCollection collection, bool reverse = false)
 {
  this._collection = collection;
  this._reverse = reverse;

  if (reverse)
  {
   this._position = collection.getItems().Count;
  }
     }

     public override object Current()
     {
  return this._collection.getItems()[_position];
     }

 public override int Key()
     {
  return this._position;
     }

 public override bool MoveNext()
 {
  int updatedPosition = this._position + (this._reverse ? -1 : 1);

  if (updatedPosition >= 0 && updatedPosition < this._collection.getItems().Count)
  {
   this._position = updatedPosition;
   return true;
  }
  else
  {
   return false;
  }
 }

 public override void Reset()
 {
  this._position = this._reverse ? this._collection.getItems().Count - 1 : 0;
     }
}
       
class WordsCollection : IteratorAggregate
{
 List<string> _collection = new List<string>();

 bool _direction = false;

 public void ReverseDirection()
     {
  _direction = !_direction;
     }

     public List<string> getItems()
     {
  return _collection;
     }

 public void AddItem(string item)
     {
  this._collection.Add(item);
     }

 public override IEnumerator GetEnumerator()
     {
  return new AlphabeticalOrderIterator(this, _direction);
     }
}

Interface class sample

static void Main(string[] args)
{
 var collection2 = new WordsCollection2();
 collection2.AddItem("First");
 collection2.AddItem("Second");
 collection2.AddItem("Third");

 Console.WriteLine("Straight traversal:");

 foreach (var element in collection2)
 {
  Console.WriteLine(element);
 }

 Console.WriteLine("\nReverse traversal:");

 collection2.ReverseDirection();

 foreach (var element in collection2)
 {
  Console.WriteLine(element);
 }

 Console.ReadKey();
}

interface Iterator2 : IEnumerator
{ 
 int Key();

 object Current();

 bool MoveNext();

 void Reset();
}

interface IteratorAggregate2 : IEnumerable
{
 new IEnumerator GetEnumerator();
}

class AlphabeticalOrderIterator2 : Iterator2
{
 object IEnumerator.Current => Current();

 private WordsCollection2 _collection;

 private int _position = -1;

 private bool _reverse = false;

 public AlphabeticalOrderIterator2(WordsCollection2 collection, bool reverse = false)
 {
  this._collection = collection;
  this._reverse = reverse;

  if (reverse)
  {
       this._position = collection.getItems().Count;
  }
     }

     public object Current()
     {
  return this._collection.getItems()[_position];
     }

 public int Key()
     {
  return this._position;
     }

 public bool MoveNext()
     {
  int updatedPosition = this._position + (this._reverse ? -1 : 1);

  if (updatedPosition >= 0 && updatedPosition < this._collection.getItems().Count)
  {
   this._position = updatedPosition;
       return true;
  }
  else
  {
       return false;
  }
 }

 public void Reset()
 {
  this._position = this._reverse ? this._collection.getItems().Count - 1 : 0;
 }
}

class WordsCollection2 : IteratorAggregate2
{
 List<string> _collection = new List<string>();

 bool _direction = false;

 public void ReverseDirection()
     {
  _direction = !_direction;
     }

 public List<string> getItems()
     {
  return _collection;
     }

 public void AddItem(string item)
     {
  this._collection.Add(item);
 }

 IEnumerator IteratorAggregate2.GetEnumerator()
     {
  return new AlphabeticalOrderIterator2(this, _direction);
     }

 IEnumerator IEnumerable.GetEnumerator()
     {
  return new AlphabeticalOrderIterator2(this, _direction);
     }
}

Page: 1 2

davidsky69

View Comments

Recent Posts

API Gateway in .NET 5 with Ocelot

What is the API gateway? An API gateway is an API management tool that sits…

3 years ago

.NET 5 application with Onion architecture

The .NET 5 SDK is a kind of milestone in the .NET world. The .NET…

3 years ago

SOLID Principles – Dependency inversion principle

In object-oriented design, the dependency inversion principle is a specific methodology for loosely coupling software…

4 years ago

SOLID Principles – Interface segregation principle

In the field of software engineering, the interface segregation principle (ISP) states that no code…

4 years ago

SOLID Principles – Liskov substitution principle

Subtype Requirement: Let  be a property provable about objects  of type T. Then  should be true for objects  of type S where S is…

4 years ago

SOLID Principles – Open-closed principle

In object-oriented programming, the open–closed principle states "software entities (classes, modules, functions, etc.) should be…

4 years ago