Iterator design pattern is one of the behavioral design patterns. It is applicable to the situation when a collection of objects has to be iterated without exposing its internal structure. The whole intent is that it is of less importance how collection has been internally stored from user point of view. The user is only concerned how he/she can access a collection. Using the word “access” is a little ambiguous in this context therefore it needs more clarity.
When accessing a collection, a user can iterate over a collection in a forward or backward manner or randomly. In forward manner, starting from Zero (0) user can access collection till end and in backward manner, it’s vice versa. User can also attempt to access the items of a collection randomly. That means accessing a collection has got different meanings.
Problem Description
An online shop sells clothes. The shop does not own clothes. However, it sells clothes from various stores and it charges a brokerage on the number of clothes sold e.g. ebay. Brokerage is not important for us in this example. Therefore, we shall not talk about it in detail. Every store has got a different meaning of providing their collection of clothes to online shop interface.
Let’s say we have two stores, EspiritStore and ZaraStore. EspiritStore stores its clothes in a List collection whereas ZaraStore in an Array. Both stores implement an interface and returns an IEnumerable collection of type Clothes. Problem at the client end is that it needs two functions to iterate over the collection separately. For EspiritStore, it iterates over a List whereas for ZaraStore over an Array.
Well, at the outset, it is not important for stores to expose how their elements are internally stored. Online Shop should only be concerned to iterate over a collection without having to know their internal structure e.g. Array, List or Dictionary etc.
Solution
From online shop point of view, it is only concerned about if a collection has items and if that’s the case, it should be able to access them. In principle, every store should provide an iterator that should implement an interface with the following two methods:
- public interface ITerator{
- bool hasNext();
- object Next();
- }
Advantage of following this approach is that stores instead of returning access to their internal data structure can return Iterators and encapsulate whole accessing of their data structures in their respective iterators.
An example of the approach has been shown below:
hasNext() method should check if element has got items in the collection based on a incrementing position number.
Next() method returns an Object from collection which can be later casted to an expected type.
- public class EspiritStoreIterator : ITerator
- {
- private readonly List<Item> _listOfItems;
-
- private int Position = 0;
-
- public EspiritStoreIterator(List<Item> listOfItems)
- {
- _listOfItems = listOfItems;
- }
-
- public bool hasNext()
- {
- if (Position>_listOfItems.Count-1)
- return false;
- return !_listOfItems.ElementAt(Position).Equals(null);
-
- }
-
- public object Next()
- {
- return _listOfItems.ElementAt(Position++);
- }
- }
Each store creates and returns an iterator to the client therefore no longer exposes the whole data structure.
- public class EspiritStore : VirtualStore
- {
-
- readonly List<Item> _listOfItems= new List<Item>();
-
- public override void AddItemsInStore()
- {
- addItemsInStore();
- }
-
- private void addItemsInStore()
- {
- _listOfItems.Add(new Item() {Name = "Shirt", Description = "Sommer", Price = 20, Size = 40});
- _listOfItems.Add(new Item() { Name = "Hose", Description = "winter", Price = 50, Size = 45 });
- }
-
-
-
-
-
-
- public ITerator CreateIterator()
- {
- return new EspiritStoreIterator(_listOfItems);
- }
- }
Now with the current implementation, it becomes easy for client (online shop) to access an iterator given a store type (shown below):
- internal class OnlineWindow
- {
- private readonly EspiritStore _espiritStore;
- private readonly ZaraStore _zaraStore;
-
- public OnlineWindow(EspiritStore espiritStore, ZaraStore zaraStore)
- {
- _espiritStore = espiritStore;
- _zaraStore = zaraStore;
- }
-
-
- public void PopulateWindow()
- {
- Console.WriteLine("Items from Espirit Store\n");
- ITerator iTerator = _espiritStore.CreateIterator();
-
- Console.WriteLine("Items from Espirit Store\n");
- PrintStoreItems(iTerator);
-
- iTerator = _zaraStore.CreateIterator();
-
-
- Console.WriteLine("\n");
- Console.WriteLine("Items from Zara Store\n");
- PrintStoreItems(iTerator);
- }
-
- private void PrintStoreItems(ITerator iTerator)
- {
- while (iTerator.hasNext())
- {
- Console.WriteLine((Item) iTerator.Next());
- }
- }
- }
PopulateWindow() access iterators of stores through CreateIterator() method and pass them to PrintStoreItems method to print them. Now Online Shop does not need two methods separately to print each store items.
In my example, I have created my own Iterator but almost in all language these iterators are provided by their own framework. In Java, this feature is supported by Iterator Interface, whereas .NET provides IEnumerable Interface.
Now that we have seen an Iterator, let’s define different players in the pattern.
Participants - Iterator: An abstract class how elements of a collection can be accessed.
- ConcreteIterator: ZaraStoreIterator and EspiritStoreIterator are the concreate iterators implement Abstract Iterator. They also hold the current Position of the tracked item in the collection.
- Aggregate: An abstract class which each store should implement and provide implementation of CreateIterator method.
- ConcreteAggregate: EspiritStore and ZaraStore are concrete classes playing role of an aggregate. They create concrete aggregate holding the collection and providing homogenous access and traversal to items in the collection.
A concrete Iterator keeps track of the current item in the aggregate and can return the next item in the aggregated collection.
As stated above, .NET framework also provides IEnumerable iterator interface. I have provided implementation using IEnumerable interface in the project attached. I suggest readers to have a look on that to understand the interface better.
So as to summarize, Iterators are widely used in Object Oriented Programming. Almost all collection classes offer iterators in one or other form. To know more about iterators, refer to MSDN.