1. Usage
- Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
- makes possible to decouple collection classes and algorithms.
- Promote to “full object status” the traversal of a collection.
- Polymorphic traversal
2. UML class diagram
3. Pros
- shields the client from the internal representation of aggregator.
- aggregate can be iterated in many different ways.
- more than one iterator can be active – the iterator stores the current state so each is self contained.
4. Cons
- uses AbsractFactory so have to define a ConcreteAggregate in addition to ConcreteIterator
- if the underlying aggregate is updated while using an Iterator, the operation of the Iterator may be undefined.
5. Source code
// http://patterns.pl/iterator.html #include <iostream> #include <vector> #include <memory> #include <stdexcept> using namespace std; template<typename T> class Iterator { public: virtual void first() = 0; virtual void next() = 0; virtual bool isDone() const = 0; virtual T& current() = 0; }; template<typename T> class VectorIterator : public Iterator<T> { vector<T> vect; size_t position; public: VectorIterator(vector<T> & v) : vect(v), position(0) {} void first() override { position = 0; } void next() override { ++position; } bool isDone() const override { return !(position < vect.size()); } T& current() override { if (!isDone()) { return vect.at(position); } throw out_of_range("out of range"); } }; int main() { vector<int> v{ 1, 2, 3 }; VectorIterator<int> vIter(v); // use interface so you can switch easly in case different implementation Iterator<int> &iter = vIter; for (iter.first(); !iter.isDone(); iter.next()) { cout << iter.current() << endl; } return 0; }