Provides a way to sequentially access elements of collection without exposing its underlying representation.
- 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:
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:
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:
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.
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 called
HasNext() 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
- Iterator interface must have a method to go to the next sequence. Typical names are
MoveNext(). 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
Hashtable. Let us take
Arraylist as our example of concrete aggregate. It implements
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 has methods named
Current. .NET Framework has played a little trick here.
MoveNext() method returns
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 “
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
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)
Let us see IL for this(simplified):
IL_0009: callvirt instance class [mscorlib]
IL_000f: br.s IL_001e
IL_0012: callvirt instance object[mscorlib]
IL_0017: call object [mscorlib]
IL_001f: callvirt instance bool [mscorlib]
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
Hashtable or to provide containment. If they provide containment, then it won’t allow you to use
for each. Try it! Let me remind you, it has to cast to
for 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 iterator
BooksEnumerator, rather name it as
CommonArraylistEnumerator and use it from
Racks … all collections which internally use
Public Class Book
Private mName As String
Public Sub New(ByVal bookName As String)
mName = bookName
Public Property Name() As String
Set(ByVal Value As String)
mName = Value
Public Class Books
Private mList As New ArrayList
Public Sub Add(ByVal bk As Book)
Default Public ReadOnly Property List(ByVal index As Integer) As Book
Return DirectCast(mList(index), Book)
Public Function GetEnumerator() As System.Collections.IEnumerator _
Return New BooksEnumerator(mList)
Private index As Integer = -1
Private mList As ArrayList
Friend Sub New(ByVal list As ArrayList)
mList = list
Public ReadOnly Property Current() As Object _
Public Function MoveNext() As Boolean _
If index < mList.Count - 1 Then
index += 1
Public Sub Reset() Implements System.Collections.IEnumerator.Reset
index = 0
- 6th September, 2005: Initial post