Iterator | slide # 2 |
...Concrete vs. Polymorphic Iterators | slide # 3 |
...Using A Smart Pointer to avoid Memory Leaks | slide # 4 |
...Who Controls the iteration? | slide # 5 |
...Who Defines the Traversal Algorithm? | slide # 6 |
...How robust is the iterator? | slide # 7 |
...Additional Iterator Operations | slide # 7 |
Visitor | slide # 10 |
...Who is Responsible for traversing the Structure? | slide # 15 |
...Why not use method overloading? | slide # 16 |
...When to Use Visitor | slide # 18 |
Vector listOfStudents = new Vector(); // code to add students not shown Enumeration list = listOfStudents.elements(); while ( list.hasMoreElements() ) Console.println( list.nextElement() ); Hashtable anIndex = new Hashtable(); // code to add elements to the hashtable not shown Enumeration list = anIndex.keys(); while ( list.hasMoreElements() ) Console.println( list.nextElement() );
Vector listOfStudents = new Vector(); // code to add students not shown VectorIterator list = new VectorIterator( listOfStudents ); while ( list.hasMoreElements() ) Console.println( list.nextElement() );Polymorphic
Vector listOfStudents = new Vector(); // code to add students not shown Enumeration list = listOfStudents.elements(); while ( list.hasMoreElements() ) Console.println( list.nextElement() );Polymorphic iterators can cause problems with memory leaks in C++ because they are on the heap!
template <class Item> class SmartPointer { public: SmartPointer( <Item>* aPointee ); ~SmartPointer( ) { delete pointee; } <Item>* operator->() { return pointee; } <Item>& operator*() { return *pointee; } private: // Can not allow multiple copies of pointee // hide copy and assignment SmartPointer( const SmartPointer& ); SmartPointer& operator=(const SmartPointer& ); <Item>* pointee; } void sample() { SmartPointer safe( new Vector() ); safe->append( "This should work" ); }
Vector listOfStudents = new Vector(); // code to add students not shown VectorIterator list = new VectorIterator( listOfStudents ); while ( list.hasMoreElements() ) Console.println( list.nextElement() );
Vector listOfStudents = new Vector(); // code to add students not shown while ( listOfStudents.hasMoreElements() ) Console.println( listOfStudents.nextElement() );
In a Vector this could mean the index of the current item
In a tree structure it could mean a pointer to current node and stack of past nodes
BinaryTree searchTree = new BinaryTree(); // code to add items not shown Iterator aSearch = searchTree.getIterator(); Iterator bSearch = searchTree.getIterator(); Object first = searchTree.nextElement( aSearch ); Object stillFirst = searchTree.nextElement( bSearch );
On Vector class, why not have a reverseIterator which goes backwords?
In a complex structure the iterator may need access to the iteratee's implementation
Vector listOfStudents = new Vector(); // code to add students not shown VectorIterator list = new VectorIterator( listOfStudents ); list.removeElementAt( 5 ); while ( list.hasMoreElements() ) Console.println( list.nextElement() );
class SelectIterator { Enumeration iteratee; public SelectionIterator( Vector newIteratee ) { iteratee = newIteratee.elements(); } public select( Command condition ) { Vector selected = new Vector(); while ( iteratee.hasMoreElements() ) { Object candidate = iteratee.nextElement(); if ( condition.execute( candidate ) ) selected.addElement( candidate ) } return selected; } }
class StringContains extends Command { String searchString; public StringContains( String aString ) { searchString = aString; } public boolean execute( Object aString ) { return ((String) aString)).contains( searchString ); } } Vector studentList = new Vector(); // code adding student not shown SelectionIterator findName = new SelectionIterator( studentList ); Vector theBills = findName.select( new StringContains( "bill" ) ); Vector theJoses = findName.select( new StringContains( "jose" ) );Smalltalk Equivalent of Entire Example
Vector studentList = new Vector();
// code adding student not shown
Vector theBills, theJoses; theBills = studentList.select( [ ( x ) | return x.contains("bill") ]); theJoses = studentList.select( [ ( x ) | return x.contains("jose") ]);
class BinaryNode extends Node { private Node left = null; private Node right = null; private Object data; public void setLeftChild( Node addMe ) { left = addMe; } public void setRightChild( Node addMe ) { right = addMe; } public void setData( Object newData) { data = newData; } public String print() { return left.print() + data.toString() + right.print(); } }What about preorder visit, postorder visit?
class PreorderIterator { private Node currentNode; public PreorderIterator( Node aNode ) { currentNode = aNode; } // lots of stuff not shown } class PostorderIterator { blah }
Node root = new BinaryNode(); // code adding nodes not shown PreorderIterator treeList = new PreorderIterator( root ); while ( treeList.hasMoreElements() ) Console.print( treeList.nextElement() );
abstract class Node { private Object data = null; abstract public void accept( NodeVisitor visitor ); public void setData( Object newData ) { data = newData; } public void getData( ) { return data; } } class BinaryNode extends Node { private Node left = null; private Node right = null; public void setLeftChild( Node addMe ) { left = addMe;} public void setRightChild( Node addMe ) { right = addMe; } public void getLeftChild() { return left; } public void getRightChild() { return right; } public void accept( NodeVisitor visitor ) { left.accept( visitor); right.accept( visitor); visitor.visitBinaryNode( this ); } }
class Leaf extends Node { public void accept( NodeVisitor visitor ) { visitor.visitLeaf( this ); } } class SingleNode extends Node { private Node child = null; public void setChild( Node addMe ) { child = addMe; } public void getChild() { return child; } public void accept( NodeVisitor visitor ) { child.accept( this ); visitor.visitSingleNode( this ); } }
abstract class NodeVisitor { abstract public void visitLeaf( Leaf toVisit); abstract public void visitBinaryNode( BinaryNode toVisit); abstract public void visitSingleNode( SingleNode toVisit); }
class ExpressionEvaluator extends NodeVisitor { Stack values = new Stack(); public void visitLeaf( Leaf toVisit) { values.push( toVisit.getData() ); } public void visitBinaryNode( BinaryNode toVisit) { Number rightOperand = (Number) values.pop(); Number leftOperand = (Number) values.pop(); Number result; char operator = (char) toVisit.getData(); switch ( operator ) { case '+': result = leftOperand + rightOperand;break; case '/': result = leftOperand / rightOperand;break; } values.push( result ); } public void visitSingleNode( SingleNode toVisit) { Number operand = (Number) values.pop(); Number result; String operator = (String) toVisit.getData(); switch ( operator ) { case "-": result = -1 * operand; break; case "++": result = operand + 1; break; } values.push( result ); }
Node root = new BinaryNode(); // code adding nodes not shown ExpressionEvaluator aVisitor = new ExpressionEvaluator(); root.accept( aVisitor );
abstract class Node { private Object data = null; abstract public void accept( NodeVisitor visitor ) { visitor.visit( this ); } public void setData( Object newData ) { data = newData; } public void getData( ) { return data; } } class BinaryNode extends Node { private Node left = null; private Node right = null; public void setLeftChild( Node addMe ) { left = addMe;} public void setRightChild( Node addMe ) { right = addMe; } public void getLeftChild() { return left; } public void getRightChild() { return right; } }
abstract class NodeVisitor { abstract public void visit( Leaf toVisit); abstract public void visit( BinaryNode toVisit); abstract public void visit( SingleNode toVisit); }
class SingleNode extends Node { private Node child = null; public void setChild( Node addMe ) { child = addMe; } public void getChild() { return child; } }
class ExpressionEvaluator extends NodeVisitor { Stack values = new Stack(); public void visit( Leaf toVisit) { values.push( toVisit.getData() ); } public void visit( BinaryNode toVisit) { // Same as visitBinaryNode in earlier example } public void visit( SingleNode toVisit) { Number operand = (Number) values.pop(); Number result; String operator = (String) toVisit.getData(); switch ( operator ) { case "-": result = -1 * operand; break; case "++": result = operand + 1; break; } values.push( result ); }
Note this example assumes traversal is in an iterator