Iterator Pattern






3.08/5 (24 votes)
Iterator pattern well described
Introduction
GoF Definition
Provides a way to sequentially access elements of collection without exposing its underlying representation.
Let's Understand
- Sequential access elements.
Think about this. Every collection could have different logic for storing elements and even different logic to determine sequence. - Of collection.
What we are iterating through is collection. This could be any collection. All we care about is it is a collection that should allow us to iterate in common way. Thinking about interface implementation? You are right. - Without exposing its underlying representation.
Collection should give something which will allow us to iterate through – also follows standard. Here we are talking about some separate object which implements concrete implementation. Yes, follow OO standard, create a separate class for this, which is specialized from some generalized mechanism.
Now let's see how many different types we talked about so far. First things first, we need collection(s) or aggregate(s).
So my first class in model: ConcreteAggregate
.
This aggregate must have some common standard way to return iterating mechanism. When we talk about a standard without common implementation, we would select interface.
So my interface: Aggregate
.
Guys, we are talking about some common mechanism all the time. What is this? Let us give some name. For a particular aggregate, I will have a particular mechanism, which allows to iterate through.
Let me call the concrete implementation class: ConcreteIterator
.
Should the concrete iterator follow some standard so that we can access it through standard methods and the client will never come to know who did the job. Again standard! Again interface.
Interface: Iterator
.
UML Diagram
Let us put together all of the above. I have some concrete aggregates that implement some common aggregate interface:

I should have a concrete iterator that implements standard iterator interface.

My concrete aggregate should return me a concrete iterator through aggregate interface implementation.

Finally, the client should have access to the following:
- Concrete aggregate
- Aggregate interface
- Iterator interface
Hey! This is not fair. The client is aware of everyone else but concrete iterator. Buddy, that’s what we want. Do you remember the phrase “without exposing its underlying representation”? So let's prepare our complete diagram:

Forward to Method Definitions
Let's go through sequence:
- Client will cast the concrete aggregate-to-aggregate interface to use standard method(s).
- Client will define variable of interface iterator type and set it through some method of aggregate interface. I got a method of aggregate interface:
GetIterator()
which returns iterator type. - Client will write
while
loop to iterate. The condition to loop is that the iterator should have next sequence object available. So iterator should have a method calledHasNext()
which returns Boolean. - If next object exist, client needs to get next sequence object as well move iterator pointer to its next at once. Client will call some method named:
MoveNext()
which moves sequence of iterator plus one and return next sequent object. - Use client object.
Finally, I have classes defined with methods as below:

Rules to Follow
- Aggregate interface must have a method that returns iterator interface. This could be named anything. Commonly used names are
CreateIterator()
orGetIterator()
. - Iterator interface must have a method to go to the next sequence. Typical names are
Next()
orMoveNext()
. This method must return a sequential object and adds sequence with 1. - Iterator should keep track of position.
- Concrete iterator must take concrete aggregate’s storing way as an argument in the constructor. Storing way could be array arraylist or any complex logic that only the concrete iterator and concrete aggregate may understand.
- Concrete iterator’s constructor should only be accessible from concrete aggregate(s). Make the constructor as project level – “
internal
” in C# and “Friend
” in VB.NET.
Any Standard Examples in the Market?
Of course, yes. Let us understand what C# or VB.NET does with collections:
.NET framework has aggregate interface called IEnumerable
and has iterator interface called IEnumerator
. There are some concrete aggregates like Arraylist
and Hashtable
. Let us take Arraylist
as our example of concrete aggregate. It implements Ienumberable
. Ienumberable
interface has a method named GetEnumerator()
. This was our rule #1.
Arraylist
has a class named ArraylistEnumeratorSimple
which functions as a concrete iterator for us. ArraylistEnumeratorSimple
class implements IEnumerator
. IEnumerator
has methods named MoveNext()
and Current
. .NET Framework has played a little trick here. MoveNext()
method returns Boolean
and Current
provides current object. By doing this, .NET provides extra facility to get the same sequence object again if you want. (Do I really want the same object again? Never, as I have already set to some variable in client code so why should I use IEnumerator
’s current and why not client’s local variable. .NET knows! Anyway, it's better so doesn’t matter. It followed our rule #2 and #3. Rule #3? Internally it keeps track of position which is private
with variable name “index
”.
ArraylistEnumeratorSimple
is declared as inner class of ArrayList
and its constructor is internal and takes arraylist
itself as parameter. This follows rule #4 and #5.
The only words I may expect now: “What is the use of all these? I never cast my ArrayList
as Ienumerable
, never call GetIterator()
method. This is all junk!” Take a chill-pill. Let us write a simple call iterating through ArrayList
in C# or VB.NET:
ArrayList al = new ArrayList();
Foreach(object o in object)
{
//use o
}
Let us see IL for this(simplified):
IL_0008: ldloc.0
IL_0009: callvirt instance class [mscorlib]
System.Collections.IEnumerator [mscorlib]
System.Collections.ArrayList::GetEnumerator()
IL_000e: stloc.2
IL_000f: br.s IL_001e
IL_0011: ldloc.2
IL_0012: callvirt instance object[mscorlib]
System.Collections.IEnumerator::get_Current()
IL_0017: call object [mscorlib]
System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)
IL_001c: stloc.1
IL_001d: nop
IL_001e: ldloc.2
IL_001f: callvirt instance bool [mscorlib]
System.Collections.IEnumerator::MoveNext()
IL_0024: brtrue.s IL_0011
IL_0026: leave.s IL_003f
Have fun! C# and VB.NET provide little additional facility to developers by giving keyword “for each
” which internally writes the same code.
Where to Use in my Day-to-Day Programming?
- Do you use strongly typed collections in your application? Use this pattern. See the sample code in next section. A typical developer has a confusion whether to subclass
Arraylist
orHashtable
or to provide containment. If they provide containment, then it won’t allow you to usefor each
. Try it! Let me remind you, it has to cast toIEnumerable
infor each
loop. - You can have one concrete iterator for similar type of collections. For example, if you are using
Arraylist
as your collection mechanism internally and don’t have any specific logic for sequence, then the same concrete iterator will work for those collections. For example, in the below mentioned example, there is a concrete iteratorBooksEnumerator
, rather name it asCommonArraylistEnumerator
and use it fromBooks
,Computers
, andRacks
… all collections which internally useArrayList
.
Sample Code
Public Class Book
Private mName As String
Public Sub New(ByVal bookName As String)
mName = bookName
End Sub
Public Property Name() As String
Get
Return mName
End Get
Set(ByVal Value As String)
mName = Value
End Set
End Property
End Class
Public Class Books
Implements IEnumerable
Private mList As New ArrayList
Public Sub Add(ByVal bk As Book)
mList.Add(bk)
End Sub
Default Public ReadOnly Property List(ByVal index As Integer) As Book
Get
Return DirectCast(mList(index), Book)
End Get
End Property
Public Function GetEnumerator() As System.Collections.IEnumerator _
Implements System.Collections.IEnumerable.GetEnumerator
Return New BooksEnumerator(mList)
End Function
Class BooksEnumerator
Implements IEnumerator
Private index As Integer = -1
Private mList As ArrayList
Friend Sub New(ByVal list As ArrayList)
mList = list
End Sub
Public ReadOnly Property Current() As Object _
Implements System.Collections.IEnumerator.Current
Get
Return mList(index)
End Get
End Property
Public Function MoveNext() As Boolean _
Implements System.Collections.IEnumerator.MoveNext
If index < mList.Count - 1 Then
index += 1
Return True
Else
Return False
End If
End Function
Public Sub Reset() Implements System.Collections.IEnumerator.Reset
index = 0
End Sub
End Class
End Class
History
- 6th September, 2005: Initial post