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