The Iterator design pattern is a behavioral pattern that provides a way to access elements of a collection sequentially without exposing its underlying representation. This pattern is useful for traversing different data structures in a uniform way.
Understanding the Memento Design Pattern in C#
Let's consider a scenario where we have a Book
class and a BookCollection
class. We want to iterate over the BookCollection
without exposing its internal details.
Example without Iterator Design Pattern
using System; using System.Collections.Generic; namespace WithoutIteratorPattern { // Book class class Book { public string Title { get; private set; } public Book(string title) { Title = title; } } // Concrete collection class BookCollection { private readonly List<Book> _books = new List<Book>(); public int Count => _books.Count; public Book this[int index] => _books[index]; public void AddBook(Book book) { _books.Add(book); } public List<Book> GetBooks() { return _books; } } class Program { static void Main(string[] args) { BookCollection collection = new BookCollection(); collection.AddBook(new Book("Design Patterns")); collection.AddBook(new Book("Clean Code")); collection.AddBook(new Book("Refactoring")); List<Book> books = collection.GetBooks(); Console.WriteLine("Iterating over collection:"); for (int i = 0; i < books.Count; i++) { Console.WriteLine(books[i].Title); } } } }
Problems in the Non-Pattern Approach
- Lack of Abstraction:The client code (in
Program.Main
) directly accesses the internal representation of the collection (List<Book>
). This means any change in the collection type (e.g., fromList<Book>
to another collection type) requires changes in the client code. - Limited Flexibility:If different iteration behaviors are needed (e.g., reverse iteration, skipping certain elements), the client code must be modified, making it less flexible and harder to maintain.
- Code Duplication:Each time we need to iterate over the collection, we would write similar looping code, leading to code duplication and potential inconsistencies.
- Encapsulation Violation:Exposing the internal list of books through
GetBooks()
method breaks encapsulation, making it possible for the client code to modify the collection directly, which can lead to unexpected behaviors.
How Iterator Pattern Solves These Problems
- Encapsulation:The Iterator Pattern encapsulates the iteration logic inside the iterator. The client code interacts with the collection through the iterator interface, without knowing or depending on the underlying collection structure.
- Single Responsibility:The collection class (
BookCollection
) is responsible for managing the collection of books, and the iterator class (BookIterator
) is responsible for the iteration logic. This separation of concerns makes the code more modular and easier to maintain. - Flexibility:Different iteration behaviors can be implemented by creating different iterators. For example, if you need a reverse iterator, you can create a
ReverseBookIterator
without changing the client code. - Consistency:The iteration logic is centralized in the iterator, reducing code duplication and ensuring consistent behavior across different parts of the application.
Revisited Code with Iterator Pattern
Here is how we can implement this pattern:
using System; using System.Collections; using System.Collections.Generic; namespace IteratorPattern { // Book class class Book { public string Title { get; private set; } public Book(string title) { Title = title; } } // Iterator interface interface IIterator<T> { T Current { get; } bool MoveNext(); void Reset(); } // Concrete iterator class BookIterator : IIterator<Book> { private readonly BookCollection _collection; private int _currentIndex = -1; public BookIterator(BookCollection collection) { _collection = collection; } public Book Current => _collection[_currentIndex]; public bool MoveNext() { _currentIndex++; return _currentIndex < _collection.Count; } public void Reset() { _currentIndex = -1; } } // Collection interface interface IBookCollection { IIterator<Book> CreateIterator(); int Count { get; } Book this[int index] { get; } } // Concrete collection class BookCollection : IBookCollection { private readonly List<Book> _books = new List<Book>(); public int Count => _books.Count; public Book this[int index] => _books[index]; public void AddBook(Book book) { _books.Add(book); } public IIterator<Book> CreateIterator() { return new BookIterator(this); } } class Program { static void Main(string[] args) { BookCollection collection = new BookCollection(); collection.AddBook(new Book("Design Patterns")); collection.AddBook(new Book("Clean Code")); collection.AddBook(new Book("Refactoring")); IIterator<Book> iterator = collection.CreateIterator(); Console.WriteLine("Iterating over collection:"); while (iterator.MoveNext()) { Console.WriteLine(iterator.Current.Title); } } } }
Comments
Post a Comment