Iterator - Design Pattern


Objective ๐ฏ
Provide a way to access elements of a list sequentially without exposing its underlying representation.
Type โ
โ๏ธBehavioral: Describes how objects interact/communicate between themselves.
โCreational: Describes how to instantiate an object without large and complex.
โStructural: Describes how objects/classes are composed to form larger structures.
UML ๐
Participants ๐
โข Iterator:
- Defines an interface to access elements in the collection
โข ConcreteIterator:
- Implements the Iterator interface
- Keeps track of the current position in the traversal of the collection
โข Aggregate:
- Defines the interface of the Iterator object that will manipulate the collection
โข ConcreteAggregate:
- Responsible for maintaining the real list of objects that will be manipulated
- Implements the Aggregate interface and its method to return a ConcreteIterator
Notes ๐
โข In the ConcreteAggregate object, an Indexer must be implemented to avoid external manipulation to the list items.
Sample Code ๐ฎ
Structural Example ๐๏ธ
public static class IteratorStructural
{
public static void Execute()
{
ConcreteAggregate lConcreteAggregate = new ConcreteAggregate();
lConcreteAggregate[0] = "Item A";
lConcreteAggregate[1] = "Item B";
lConcreteAggregate[2] = "Item C";
lConcreteAggregate[3] = "Item D";
// Create Iterator and provide aggregate
ConcreteIterator lConcreteIterator = new ConcreteIterator(lConcreteAggregate);
Console.WriteLine("Iterating over collection:");
object lobject = lConcreteIterator.First();
while (lobject != null)
{
Console.WriteLine(lobject);
lobject = lConcreteIterator.Next();
}
}
}
public abstract class Aggregate
{
public abstract Iterator CreateIterator();
}
public class ConcreteAggregate : Aggregate
{
private ArrayList _Items = new ArrayList();
public override Iterator CreateIterator()
{
return new ConcreteIterator(this);
}
public int Count
{
get { return _Items.Count; }
}
public object this[int prIndex]
{
get { return _Items[prIndex]; }
set { _Items.Insert(prIndex, value); }
}
}
public abstract class Iterator
{
public abstract object First();
public abstract object Next();
public abstract bool IsDone();
public abstract object CurrentItem();
}
public class ConcreteIterator : Iterator
{
private ConcreteAggregate _ConcreteAggregate;
private int _CurrentElement = 0;
public ConcreteIterator(ConcreteAggregate prConcreteAggregate)
{
_ConcreteAggregate = prConcreteAggregate;
}
public override object First()
{
return _ConcreteAggregate[0];
}
public override object Next()
{
object lResult = null;
if (_CurrentElement < _ConcreteAggregate.Count - 1)
{
lResult = _ConcreteAggregate[++_CurrentElement];
}
return lResult;
}
public override object CurrentItem()
{
return _ConcreteAggregate[_CurrentElement];
}
public override bool IsDone()
{
return _CurrentElement >= _ConcreteAggregate.Count;
}
}
Output
Real-world Example ๐ฅ
public static class IteratorPractical
{
public static void Execute()
{
OfficeFiles lOfficeFiles = new OfficeFiles();
lOfficeFiles[0] = new File() { Name = "File001_PB", IsPrivate = false };
lOfficeFiles[1] = new File() { Name = "File002_PV", IsPrivate = true };
lOfficeFiles[2] = new File() { Name = "File003_PB", IsPrivate = false };
lOfficeFiles[3] = new File() { Name = "File004_PV", IsPrivate = true };
lOfficeFiles[4] = new File() { Name = "File005_PB", IsPrivate = false };
lOfficeFiles[5] = new File() { Name = "File006_PV", IsPrivate = true };
FileIterator lFileIterator = lOfficeFiles.CreateIterator();
Console.WriteLine("Iterating over files using \"Public File Iterator\": ");
File lFile = lFileIterator.First();
Console.WriteLine("First File: " + lFile.Name);
lFile = lFileIterator.Next();
Console.WriteLine("Next File: " + lFile.Name);
List<File> lFiles = lFileIterator.GetAll();
Console.WriteLine("All Files: " + String.Join(", ", lFiles.Select(X => X.Name).ToList()));
lFileIterator = new PrivateFileIterator(lOfficeFiles);
Console.WriteLine("\n\rIterating over files using \"Private File Iterator\": ");
lFile = lFileIterator.First();
Console.WriteLine("First File: " + lFile.Name);
lFile = lFileIterator.Next();
Console.WriteLine("Next File: " + lFile.Name);
lFiles = lFileIterator.GetAll();
Console.WriteLine("All Files: " + String.Join(", ", lFiles.Select(X => X.Name).ToList()));
}
}
// Aggregate (Concrete)
public class OfficeFiles
{
private ArrayList _Items = new ArrayList();
public FileIterator CreateIterator()
{
return new PublicFileIterator(this);
}
public int Count
{
get { return _Items.Count; }
}
public object this[int prIndex]
{
get { return _Items[prIndex]; }
set { _Items.Insert(prIndex, value); }
}
}
// Iterator
public abstract class FileIterator
{
public abstract File First();
public abstract File Next();
public abstract List<File> GetAll();
public abstract File CurrentItem();
}
// Concrete Iterator
public class PublicFileIterator : FileIterator
{
private OfficeFiles _OfficeFiles;
private int _CurrentElement = 0;
public PublicFileIterator(OfficeFiles prOfficeFiles)
{
_OfficeFiles = prOfficeFiles;
this.First(); // To set the correct _CurrentElement
}
public override File First()
{
for (int i = 0; i < _OfficeFiles.Count; i++)
{
if (((File)_OfficeFiles[i]).IsPrivate == false)
{
_CurrentElement = i;
return ((File)_OfficeFiles[_CurrentElement]);
}
}
return null;
}
public override File Next()
{
object lResult = null;
for (int i = _CurrentElement; i < _OfficeFiles.Count; i++)
{
_CurrentElement++;
if (((File)_OfficeFiles[_CurrentElement]).IsPrivate == false)
return ((File)_OfficeFiles[_CurrentElement]);
}
return null;
}
public override List<File> GetAll()
{
List<File> lResult = new List<File>();
for (int i = 0; i < _OfficeFiles.Count; i++)
{
if (((File)_OfficeFiles[i]).IsPrivate == false)
lResult.Add(((File)_OfficeFiles[i]));
}
return lResult;
}
public override File CurrentItem()
{
return ((File)_OfficeFiles[_CurrentElement]);
}
}
// Concrete Iterator
public class PrivateFileIterator : FileIterator
{
private OfficeFiles _OfficeFiles;
private int _CurrentElement = 0;
public PrivateFileIterator(OfficeFiles prOfficeFiles)
{
_OfficeFiles = prOfficeFiles;
_OfficeFiles = prOfficeFiles;
this.First(); // To set the correct _CurrentElement
}
public override File First()
{
for (int i = 0; i < _OfficeFiles.Count; i++)
{
if (((File)_OfficeFiles[i]).IsPrivate == true)
{
_CurrentElement = i;
return ((File)_OfficeFiles[_CurrentElement]);
}
}
return null;
}
public override File Next()
{
object lResult = null;
for (int i = _CurrentElement; i < _OfficeFiles.Count; i++)
{
_CurrentElement++;
if (((File)_OfficeFiles[_CurrentElement]).IsPrivate == true)
return ((File)_OfficeFiles[_CurrentElement]);
}
return null;
}
public override List<File> GetAll()
{
List<File> lResult = new List<File>();
for (int i = 0; i < _OfficeFiles.Count; i++)
{
if (((File)_OfficeFiles[i]).IsPrivate == true)
lResult.Add(((File)_OfficeFiles[i]));
}
return lResult;
}
public override File CurrentItem()
{
return ((File)_OfficeFiles[_CurrentElement]);
}
}
public class File
{
public string Name { get; set; }
public bool IsPrivate { get; set; }
}
Output
Source Code ๐ฒ
https://github.com/VictorLins/DesignPatterns
Subscribe to my newsletter
Read articles from Victor Lins directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Victor Lins
Victor Lins
I am a software engineer with over 10 years of experience in a huge variety of projects and architectures, some simple others considerably complex. Some of my main skills include Software Architecture, Web Development, ASP.NET Core, React.js, Entity Framework Core, Javascript, SQL and Web Services. I consider myself passionate about coding as I really fell excited about learning technologies and using them to automate and improve processes.