Title: Iterators
1Iterators
Object Behavioral
T.J. Niglio Computer Systems Engineering
Fall 2003 Software Design Documentation
2Where is the need?
- Method of accessing an objects elements
without exposing internal structure.
- Want a compact way to keep tract of which
elements have already been accessed, as well as
what is the current element.
- Might require different traversal properties
(Filtering).
3How does it work?
4How do I make one?
- Cannot simply instantiate a specific iterator
class.
So what do you do?
- Make the aggregate object responsible for the
creation of its own concrete iterator.
- Requires operation such as CreateIterator
through which clients request an iterator object.
5So what can I do now?
- Support variations in the traversals of an
aggregate. (e.g. traversing a parse tree can be
done inorder or preorder) - Makes the aggregates life simpler. No need to
provide position calculation code into your
aggregate anymore. - Multiple simultaneous traversals are allowed.
Since the ConcreteIterator is an instance of the
Abstract Iterator Class, multiple instances will
each track their own progress position.
6Implementation FAQs
- Who controls the iteration?
- External Iterator When the client has control
- Client must advance the iterator
- More flexible than internal iterators for
operations such as comparisons.
- Internal Iterator When the iterator has
control - The iterator can be given an operation which it
could apply to each element in the aggregate. - Easier than External Iterators because
iteration logic is defined for you.
7Implementation FAQs
2. Who defines the traversal algorithm?
Aggregate - Traversal algorithm can be part of
the aggregate therefore only using the
iterator as a placeholder (Cursor).
Iterator - Easy to switch algorithms on the same
aggregate, or reuse traversal code on other
aggregates. Might violate the encapsulation of
the aggregate if iterator needs access to
private variables within the aggregate.
8Implementation FAQs
3. How robust is the iterator?
- Dangerous to modify an aggregate while
traversing. - A robust iterator ensure that insertions and
removals dont interfere with traversal. - Doesnt need to copy the aggregate
- Must be registered with the aggregate so that
insertions or removals will adjust the internal
state of the iterator. - Or, traversal information can be maintained
internally by the aggregate.
9Implementation FAQs
4. Any additional iterator operations?
Minimum required operations First, Next,
IsDone, and CurrentItem
Optional useful operations Previous Positions
the iterator to the previous item.
SkipTo Useful for sorted or indexed
collections. Can skip to an object matching
certain criteria.
10Implementation FAQs
5. Using polymorphic iterators in C
Iterator object must be allocated dynamically by
a factory method.
Polymorphic Allows you to change the aggregate
class without changing the client code.
Factory Method Lets a class defer instantiation
to subclasses.
Difficult to implement in C for many reasons
including client is responsible for deleting the
iterator (error-prone especially when there are
multiple exit points) Can be remedied using the
Proxy Pattern.
11Implementation FAQs
6. Iterators may have privileged access.
Iterator can be viewed as an extention of the
aggregate that created it. Known as a friend of
the aggregate. Such a relationship makes
defining multiple traversals difficult because of
the creation of multiple friends of the
aggregate. Remedy to allow the iterator
access to protected operations for accessing
important but publicly unavailable members of
the aggregate.
12Implementation FAQs
7. How are iterators used for composites?
External iterators are difficult to implement
over recursive aggregate structures like
composites. The path to the current position
must be stored. Internal Iterators can record
the current position by calling itself
recursively thereby storing the path implicitly
in the call stack. If the nodes of a composite
already have an interface for moving between
siblings, parents, and children, a cursor based
iterator would be better to just keep record of
the current position.
13Implementation FAQs
8. What about Null iterators?
NullIterator degenerate iterator thats helpful
for handling boundary conditions. Always done
with traversal IsDone operation always
evaluates to true. Used to traverse
tree-structured aggregates. At each position,
the current element creates an iterator for its
children. Aggregate elements return a concrete
iterator as normal, but leaf elements return an
instance of NullIterator making the
implementation uniform.
14Sample Code
Abstract Iterator Class Interface
Template ltclass Itemgt class Iterator
Public virtual void First() 0 virtual
void Next() 0 virtual bool IsDone() const
0 virtual Item CurrentItem() const
0 Protected Iterator()
15Sample Code
Using iterators to make printing easier Suppose
you had a List of Employees with the employees
class support the Print() operation. To print the
list, you can define a PrintEmployees operation
that takes an iterator as an argument
Void PrintEmployees (IteratorltEmployeegt
i) for(i.First() !i.IsDone() i.Next())
i.CurrentItem()-gtPrint()