CS 696: Advanced OO
| 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 ExampleVector 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