Back to: Design Patterns in C# With Real-Time Examples
Iterator Design Pattern in C# with Examples
I will discuss the Iterator Design Pattern in C# with Examples in this article. Please read our previous article discussing the basics of Behavioral Design Patterns in C#. The Iterator Design Pattern falls under the category of Behavioral Design Pattern. The Iterator pattern is a design pattern that provides a way to access the elements of a collection object sequentially without exposing its underlying representation. As part of this article, we will discuss the following pointers.
- What is the Iterator Design Pattern?
- Example to understand the Iterator Design Pattern in C#.
- Advantages of Iterator Design Pattern.
- When to use the Iterator Design Pattern in C#?
What is the Iterator Design Pattern?
The Iterator Design Pattern is a Behavioral Design Pattern that allows sequential access to the elements of an aggregate object (i.e., collection) without exposing its underlying representation. That means using the Iterator Design Pattern, we can access the elements of a collection sequentially without knowing its internal representations. This pattern provides a uniform interface for traversing different data structures.
The collections in C#, like List, ArrayList, Array, etc., are containers containing many objects. In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the elements of the container. Please look at the following image to better understand the Iterator Design Pattern.
The point that you need to remember is that the Data structure of the List will be different from the Data Structure of ArrayList and the same in the case of an Array. That means the storing mechanism of List will be different from the storing mechanism of Array and the storing mechanism of ArrayList in C#. But, we can access the elements of these collections using a foreach loop in the same manner.
So, the main use of the Iterator Design Pattern is to access the elements (object1, object2, object3, object4, etc.) of a collection (i.e., List, ArrayList, Array, etc.) sequentially.
Example to Understand the Iterator Design Pattern in C#:
Suppose we have a collection of employees. Then, we can easily iterate through the collection using either for or for each loop in C#, as shown in the below code.
Here, the for-each loop sequentially accesses the elements from the collection without exposing its internal logic, i.e., how it is accessing the elements sequentially. Is it not nice to provide a uniform interface for traversing different collections?
For example, your application may have different types of collections, such as List, Array, ArrayList, Generic Dictionary, etc. For whichever type of collection you have, you will need to traverse or iterate through the elements of the collections sequentially. The actual implementation of how to traverse different types of collections will be different, yet the client code should not be concerned about the details of the implementations. The Iterator Design Pattern helps you to hide such details and provides a generic interface for the client to traverse different types of collections, as shown in the image below.
Let us see the step-by-step implementation to achieve the above using the Iterator Design Pattern in C#. It involves two primary types:
- Iterator: Defines an interface for accessing and traversing elements.
- Aggregate: An interface for creating an Iterator object.
Step 1: Create the Collection Item
Here, we will use the following Employee class as the item of our collection. So, create a class file named Employee.cs and copy and paste the following code. The following Employee class is very straightforward. We have just created two properties and a constructor to initialize those two properties.
namespace IteratorDesignPattern { // Collection Item class Elempoyee { public int ID { get; set; } public string Name { get; set; } public Elempoyee(string name, int id) { Name = name; ID = id; } } }
Step 2: Creating Aggregate
This will be an interface that defines an operation to create an iterator object. Create a class file, IAbstractCollection.cs, and copy and paste the following code. The following interface declares one method, i.e., CreateIterator, which will create an Iterator object.
namespace IteratorDesignPattern { // Aggregate Interface interface IAbstractCollection { // The following Method is going to Return an Iterator object. // Later, we will Implement the Iterator class Iterator CreateIterator(); } }
Here, we define one method that will be implemented by the ConcreteAggregate class to return the Iterator object.
Step 3: Creating ConcreteAggregate
Create a class file, ConcreteCollection.cs, and copy and paste the following code. This class implements the IAbstractCollection and provides implementations for the CreateIterator method, which will return an instance of the Iterator object. Later, we will implement this Iterator class. We have also created one object listEmployees, to hold the list of employees. The Count property returns the number of employees. The AddEmployee method is used to add a new employee to the listEmployees collection, and the GetEmployee method returns the employee details based on the Intger Index Position from the listEmployees collection.
using System.Collections.Generic; namespace IteratorDesignPattern { // ConcreteAggregate Class // The following class going to implement the Iterator interface to return an instance of the proper ConcreteIterator class ConcreteCollection : IAbstractCollection { //The following collection object is going to hold a list of items or elements private List<Elempoyee> listEmployees = new List<Elempoyee>(); //Implementing the CreateIterator method of the IAbstractCollection interface //The following method is going to Create and return the Iterator Object //Later we will implement the Iterator public Iterator CreateIterator() { return new Iterator(this); } // The following method is going to return the count of the elements present in the collection public int Count { get { return listEmployees.Count; } } //Add items to the collection public void AddEmployee(Elempoyee employee) { listEmployees.Add(employee); } //Get items from the collection based on the Index Position //Index is started from 0 public Elempoyee GetEmployee(int IndexPosition) { return listEmployees[IndexPosition]; } } }
Step 4: Creating Abstract Iterator
Create a class file named AbstractIterator.cs and copy and paste the following code. This interface will define the operations for accessing and traversing elements in a sequence. Here, we have declared two methods, i.e., First and Next, and one property with only get accessor. This interface needs to be implemented by the Concrete Iterator Class and needs to provide implementations for these methods and properties.
namespace IteratorDesignPattern { // Iterator Interface // This is going to be an interface defining the operations for accessing and traversing elements in a sequence. interface IAbstractIterator { Elempoyee First(); Elempoyee Next(); bool IsCompleted { get; } } }
Step 5: Creating Concrete Iterator
Create a class file named Iterator.cs and copy and paste the following code. This will be a concrete class implementing the Iterator interface and providing implementations for Iterator interface methods. This class also keeps track of the element’s current position in the traversal. The following class code is self-explained, so please go through the comment lines for a better understanding.
namespace IteratorDesignPattern { // ConcreteIterator Class class Iterator : IAbstractIterator { //ConcreteAggregate variable to hold the collection elements private ConcreteCollection Collection; //The following variable is used as the Index Position //to access the elements of the collection private int Current = 0; //The following variable is used to move to the next element from the current element private readonly int Step = 1; // Constructor public Iterator(ConcreteCollection Collection) { //Initializing the ConcreteAggregate variable using Constructor this.Collection = Collection; } // Gets First Item from the Collection public Elempoyee First() { //Setting Current as 0 to access the First Element of the Sequence Current = 0; return Collection.GetEmployee(Current); } // Gets Next Item from the Collection public Elempoyee Next() { //Increase the Current Index Position by step (Step = 1), //to access the Next Element from the collection Current += Step; if (!IsCompleted) { return Collection.GetEmployee(Current); } else { return null; } } // Check whether the iteration is complete public bool IsCompleted { //When Current >= Collection.Count, means we have accessed all the elements get { return Current >= Collection.Count; } } } }
The First method is used to return the First element from the collection. The current property is used to hold the index position of the current element. The Next method returns the next element from the collection by adding a step with the current value. The IsCompleted method is used to check whether the iteration is completed. Using the constructor, we are initializing the ConcreteCollection object.
Step 6: Client Code
In our example, the Program class is going to be the Client. So, to test whether everything is working as expected, please modify the Main method of the Program class as shown below.
using System; namespace IteratorDesignPattern { public class Program { static void Main() { // Build a collection ConcreteCollection collection = new ConcreteCollection(); collection.AddEmployee(new Elempoyee("Anurag", 100)); collection.AddEmployee(new Elempoyee("Pranaya", 101)); collection.AddEmployee(new Elempoyee("Santosh", 102)); collection.AddEmployee(new Elempoyee("Priyanka", 103)); collection.AddEmployee(new Elempoyee("Abinash", 104)); collection.AddEmployee(new Elempoyee("Preety", 105)); // Create iterator Iterator iterator = collection.CreateIterator(); //looping iterator Console.WriteLine("Iterating over collection:"); for (Elempoyee emp = iterator.First(); !iterator.IsCompleted; emp = iterator.Next()) { Console.WriteLine($"ID : {emp.ID} & Name : {emp.Name}"); } Console.Read(); } } }
Output:
Iterator Design Pattern UML or Class Diagram
Let us understand the Iterator Design Pattern’s Class Diagram or UML Diagram. Please have a look at the following image.
As you can see in the above image, the Iterator Design Pattern consists of five components. They are as follows:
- Iterator (IAbstractIterator): This interface will define the operations for accessing and traversing elements in a sequence. In our example, it is the IAbstractIterator interface.
- ConcreteIterator (Iterator): This will be a concrete class implementing the Iterator interface and providing implementations for Iterator interface methods. This class also keeps track of the element’s current position in the traversal. In our example, it is the Iterator class.
- Aggregate (IAbstractCollection): This interface defines an operation to create an iterator object. In our example, it is the CreateIterator() method of the IAbstractCollection interface.
- ConcreteAggregate (ConcreteCollection): This will be a concrete class that implements the AbstractCollection interface to return an instance of the proper Concrete Iterator class, i.e., an instance of the Iterator class. In our example, it is the ConcreteCollection class.
- Client: This class will use the Iterator and Aggregate interfaces and access the elements. In our example, it is the Main method of the Program class.
Advantages of Iterator Design Pattern:
- Separation of Concerns: Decouples the algorithms for iteration from the actual collection classes.
- Multiple Traversals: Allows for simultaneous traversals of a collection in different ways.
- Uniform Interface: Provides a uniform interface for traversing different data structures.
- Encapsulation: Encapsulates the internal structure of how a collection is navigated and accessed.
When to Use Iterator Design Pattern in C#?
You need to Use the Iterator Design Pattern in C#
- When your collection has a complex data structure, and you want to hide its complexity from the client.
- When you want to provide a uniform interface for traversing different data structures.
- When you need to have multiple ways of traversing a collection.
In the next article, I will discuss Real-Time Examples of Iterator Design Patterns in C#. In this article, I try to explain the Iterator Design Pattern in C# with examples. I hope you understand the need for and use of the Iterator Design Pattern in C#.
Can you tell me under what real conditions it may be necessary to realize this pattern ?
For the different real-time scenarios, please check our next article.
https://dotnettutorials.net/lesson/real-time-examples-of-iterator-design-pattern-in-csharp/