Design Patterns (17): Iterator Patterns
Definition:
- Provides a method to traverse an aggregated object sequentially, providing the required interfaces for traversing different aggregated structures without exposing the internal representation of the object.
The main solutions are:
- Different ways to traverse the entire integration object
How to solve:
- Instead of aggregating objects, the responsibility for wandering between elements is vested in the iterator.
Take code as an example
The class diagram is as follows
Definition of Aggregate classes
Aggregate defines an interface for aggregation that separates the client from the implementation of the object set
#include <iostream> #include <stdexcept> #include <vector> class Iterator; class ConcreteAggregate; class Aggregate { public: virtual ~Aggregate() {} virtual Iterator *createIterator() = 0; // ... };
Definition of ConcreteAggregate
Concrete Aggregate has a set of objects and implements a method for returning Iterator to its collection
class ConcreteAggregate : public Aggregate { public: ConcreteAggregate( const unsigned int size ) { list = new int[size](); count = size; } ~ConcreteAggregate() { delete[] list; } Iterator *createIterator(); unsigned int size() const { return count; } int at( unsigned int index ) { return index; } // ... private: int *list; unsigned int count; // ... };
Definition of Iterator
Iterator provides the interfaces that all iterators must implement and a set of methods for traversing elements
class Iterator { public: virtual ~Iterator() { /* ... */ } virtual void first() = 0; virtual void next() = 0; virtual bool isDone() const = 0; virtual int currentItem() const = 0; // ... };
Definition of ConcreteIterator
Concrete Iterator implements interfaces that manage the current location of iterators
class ConcreteIterator : public Iterator { public: ConcreteIterator( ConcreteAggregate *l ) : list( l ), index( 0 ) {} ~ConcreteIterator() {} void first() { index = 0; } void next() { index++; } bool isDone() const { return ( index >= list->size() ); } int currentItem() const { if ( isDone() ) { return -1; } return list->at(index); } // ... private: ConcreteAggregate *list; unsigned int index; // ... };
5. Call of main function
Iterator *ConcreteAggregate::createIterator() { return new ConcreteIterator( this ); } int main() { unsigned int size = 5; ConcreteAggregate list = ConcreteAggregate( size ); Iterator *it = list.createIterator(); for ( ; !it->isDone(); it->next()) { std::cout << "Item value: " << it->currentItem() << std::endl; } delete it; return 0; }
Operation results:
Item value: 0 Item value: 1 Item value: 2 Item value: 3 Item value: 4
This simplifies the implementation of an iterator pattern
Advantages and disadvantages of iterator pattern
Advantage:
1. It supports traversing an aggregated object in different ways.
2. Iterators simplify aggregation classes.
3. There can be multiple traversals on the same aggregation.
4. In the iterator mode, it is convenient to add new aggregator classes and iterator classes without modifying the original code.
Disadvantages:
1. Because the iterator pattern separates the responsibility of storing and traversing data, adding new aggregation classes requires adding new iterator classes corresponding to increasing the number of classes in pairs, which increases the complexity of the system to a certain extent.
Matters needing attention:
- The iterator pattern separates the traversal behavior of the object, which not only does not expose the internal structure, but also allows external code to transparently access the data inside the collection.