Iterator behavioural design pattern
description
Transcript of Iterator behavioural design pattern
Iterator behavioural design Iterator behavioural design patternpattern
Eivind J. Nordby
University of Karlstad
Inst. for Information Technology
Dept. of Computer ScienceLast revised 051010
1998-09-15 Computer Science, University of
Karlstad2
Introduction Introduction
An iterator can be used in order to provide a way to access the elements of an
aggregate object sequentially without exposing its underlying representation
always used with ”containers” or ”collections”
1998-09-15 Computer Science, University of
Karlstad3
next()
The basic ideaThe basic idea
aContainer
anElement
anElement
anElement
anElement
anElement
anElement
aContainerIterator
+first()
+next()
+isDone()
+current()
current-Element*
”on” or “over”
isDone()
first()
current()
1998-09-15 Computer Science, University of
Karlstad4
Basic usageBasic usage
List* pMyList = new List;// populate the listListIterator *pli = new ListIterator(pMyList);
// Implicit or explicit: pli->first();while (!pli->isDone()) {
// do something with pli->current(); pli->next();}delete pli;
1998-09-15 Computer Science, University of
Karlstad5
Abstract iteratorsAbstract iterators
1998-09-15 Computer Science, University of
Karlstad6
Iterators: ConsequencesIterators: Consequences
They support variations in the traversal of an aggregate.– through polymorphic iteration
They simplify the Aggregate interface.– remove the iterator interface from aggregate
More than one traversal can be pending on an aggregate.
1998-09-15 Computer Science, University of
Karlstad7
Iterate Through the Positions of a Iterate Through the Positions of a Game BoardGame Board
low …
…
…
…
high…
… … … … … …
pci
pri
1998-09-15 Computer Science, University of
Karlstad8
MotivationsMotivations
Why positions and not fields?– Does not assume that there is a field
Use the iterator to populate the board with fields Use the iterator to print the fields
Why separate for columns and rows?– Allows to express explicitly the intention of the
iteration For instance row-wise printing Without knowing the implementation
Why a common base class (BoardIterator)– Same protocol for all iterators
1998-09-15 Computer Science, University of
Karlstad9
Example ClientExample Client
// <select a game, suppressed>
Board* myBoard;
myBoard = GameFactory::instance().createBoard();
// print the board row by row by
// iterating over the positions of the first column
BoardIterator *pci = myBoard->columnIterator();
while (!pci->isDone()) {
// do something at pci->current(), see next slide
pci->next(); // go on to the next game row
}
delete pci;
1998-09-15 Computer Science, University of
Karlstad10
do something with pci->current()do something with pci->current()
// iterate three times over the current row positions
const int drawRows = 3; // for each position
for (int i = 1; i <= drawRows; i++) {
BoardIterator *pri = myBoard->rowIterator(pci->current());
while (!pri->isDone()) {
out << myBoard->fieldAt(pri->current())->toString(i);
pri->next();
}
delete pri;
} OO style: create a new iterator object whenever needed rather than reusing the same
one– Simplifies logic and improves correctness
1998-09-15 Computer Science, University of
Karlstad11
Graphic alternativeGraphic alternative
For a graphic clientvoid paint(GraphicContext* gc){ Board* myBoard; myBoard = GameFactory::instance().createBoard(); myBoard->paint(gc); // iterating over the positions of the board BoardIterator *pbi = myBoard->defaultIterator(); while (!pbi->isDone()) { myBoard->fieldAt(pbi->current())->paint(gc); pbi->next(); } delete pci;} // paint
1998-09-15 Computer Science, University of
Karlstad12
A more realistic graphic wayA more realistic graphic way
In the previous example, each field needs to compute its own position on the graphic surface.
Normally, the graphic picture will consist of a lot of small views, one for each field– The board view paints the board frame– Each field view paints its field and piece– The paiting is inisialized from the operating system– No iterator is needed at all
1998-09-15 Computer Science, University of
Karlstad13
A more realistic graphic clientA more realistic graphic client
class BoardView{ Board* board; // assigned on creation void paint() {board->paint(this->graphicContext();}} // class BoarViewclass FieldView{ Field* field; void paint() { gc->foregroundColor(fgcOf(field->position()); gc->backgroundColor(bgcOf(field-’>position()); gc->inset(Point(1,1)); field->paint(this->graphicContext(); }
1998-09-15 Computer Science, University of
Karlstad14
A graphics aware modelA graphics aware model
class Field{
Piece* piece;
void paint(GraphicContext* gc){
if (piece!=0) piece->paint(gc);
gc->drawSquare(Point(0,0), gc->size());
}
} // class Field
class Piece{
Bitmap bitMap; // initialized at creation
void paint(GraphicContext* gc){gc->draw(bitMap);}
}
1998-09-15 Computer Science, University of
Karlstad15
ColumnIteratorColumnIterator
Iterate over the positions of a column– Defaults to the first column on the board– ColumnIterator(Board* board);
Alternative constructor for explicit start position– Iterate over a column starting from a given
position– ColumnIterator(Board* board, Point position);
1998-09-15 Computer Science, University of
Karlstad16
ColumnIterator FeaturesColumnIterator Features Constructors
– ColumnIterator(Board* board) // Pre: board not null
– ColumnIterator(Board* b, Point pos) // Pre: b not null
Accessors– Point current() // Post: result = current position
– bool isDone() // Post: result = current not inside board
Transformers– void next() // Post: current stepped to next position
1998-09-15 Computer Science, University of
Karlstad17
Abstract BoardIteratorAbstract BoardIterator RowIterator and ColumnIterator share
– the same protocol– the same constructors– the same implementation
except for the function next()
They are obvious candidates to share– a common (abstract/default) base class– the derived classes (re)define next()
Some ideas follow
1998-09-15 Computer Science, University of
Karlstad18
Conceptual ModelConceptual Model
positions
*
+current1
* 1
iterates over
Board
+fieldAt:Field+contains:bool+low:Point+high:Point+size:Point
RowIterator
+next:void
PointColumnIterator
+next:void
BoardIterator
+isDone:bool+next:void
1998-09-15 Computer Science, University of
Karlstad19
A Possible ImplementationA Possible Implementation
Assume the following Access methods for Board:
– Field* fieldAt(Point position);– Point low(); // lowest position– Point high(); // highest position– Point size(); // dimensions– bool contains(Point position);
Access methods for Field:– Point position();– Board *board();
1998-09-15 Computer Science, University of
Karlstad20
Design modelDesign model
_high
1
_low
1
_board
1
_current!
0..1
_position
_board
*0..1
ColumnIterator
+next:void
RowIterator
+next:void
Point
+x:int+y:int+incX:void+incY:void+setX:void+setY:void
Board
+fieldAt:Field+contains:bool+low:Point+high:Point+size:Point
BoardIterator
+isDone:bool+current:Point+next:void
Field
+toString:String
1998-09-15 Computer Science, University of
Karlstad21
class BoardIteratorclass BoardIterator Private instance variables
Point _current; // the current posBoard* _pBoard; // != null
Implementation invariant– _current.x() is fixed, identifies the
column– _current.y() is the current row number– *_pBoard is the board iterated over
Constructor(Board *board) // board != nullBoardIterator(Board *board) { _current = board->low(); _pBoard = board}
1998-09-15 Computer Science, University of
Karlstad22
class BoardIterator (cont’d)class BoardIterator (cont’d)
Public iterator access functions// void first() {_current.setY(board->low().y());}void next() {<move to next in some default order>}boolean isDone() {return !inside(_current);}Point current() {return _current;}
private:bool inside(Point position){
return board->contains(position);}
None of the operations need a precondition– Precondition !isDone() only needed when actually
accessing a position on a board– Responsibility may be delegated to the client
1998-09-15 Computer Science, University of
Karlstad23
class ColumnIteratorclass ColumnIterator Inherits BoardIterator Implementation invariant
– current().x() fixed, identifies the column– current().y() is the current row number
Constructor(Board *board) // board != nullColumnIterator(Board *board): BoardIterator(board) {}
Redefined operationvoid next() {current().incY();}
1998-09-15 Computer Science, University of
Karlstad24
RowIteratorRowIterator
Very similar to ColumnIterator– same instance variables as ColumnIterator– iterating over the positions of a row, not those
of a column In this example I show another constructor
– Taking a specific position as an argument– Iterate over a row starting from the position
1998-09-15 Computer Science, University of
Karlstad25
class RowIteratorclass RowIterator
Public constructorsBoardIterator(Board *pb, Point start) {
_current = start; _pBoard = pb;}...RowIterator(Board *pb, Point start): BoardIterator(pb, start) {}
Redefined access function– void next() {current().incX();}