CS 696: Advanced OO
| Builder | slide # 1 |
| ...Intent | slide # 1 |
| ...Applicability | slide # 1 |
| ...Collaborations | slide # 2 |
| ...Example - RTF Converter | slide # 3 |
| ...Consequences | slide # 8 |
| Factory Method | slide # 9 |
| ...Example - Maze Game | slide # 9 |
| ......Maze Class Version 1 | slide # 10 |
| ...Implementation | slide # 14 |
| ......Parameterized Factory Methods | slide # 15 |
| ......C++ Templates to Avoid Subclassing | slide # 15 |
| ......Java forName and Factory methods | slide # 16 |
| ......Clients Can Use Factory Methods | slide # 17 |
Director notifies the builder whenever a part of the product should be built
Builder handles requests from the director and adds parts to the product
The client retrieves the product from the builder

| words paragraphs fonts - times, courier, etc. fonts sizes fonts styles - bold, italic, etc. subscripts, superscripts, etc headings | style sheets page numbers page breaks images equations tables |
RTF (Rich Text Format) is one of several standard formats for
converting documents between applications and hardware
platforms
The problem is to write a program to convert RTF to other document formats:
class RTF_Reader
{
TextConverter builder;
String RTF_Text;
public RTF_Reader( TextConverter aBuilder, String RTFtoConvert )
{
builder = aBuilder;
RTF_Text = RTFtoConvert;
}
public void parseRTF()
{
RTFTokenizer rtf = new RTFTokenizer( RTF_Text );
while ( rtf.hasMoreTokens() )
{
RTFToken next = rtf.nextToken();
switch ( next.type() )
{
case CHAR: builder.character( next.char() ); break;
case FONT: builder.font( next.font() ); break;
case PARA: builder.newParagraph( ); break;
etc.
}
}
}
}
More Outlineabstract class TextConverter
{
public void character( char nextChar ) { }
public void font( Font newFont ) { }
public void newParagraph() {}
}
class ASCII_Converter extends TextConverter
{
StringBuffer convertedText = new StringBuffer();
public void character( char nextChar )
{
convertedText.append( nextChar );
}
public String getASCII_Text()
{
return convertedText.toString();
}
}
class TeX_Converter extends TextConverter
{
public void character( char nextChar ) { blah }
public void font( Font newFont ) { blah }
public void newParagraph() { blah }
public TeX getTeX_Text() { return the correct thing }
}
Main Program
main()
{
ASCII_Converter simplerText = new ASCII_Converter();
String rtfText;
// read afile of rtf into rtfText
RTF_Reader myReader = new RTF_Reader( simplerText, rtfText );
myReader.parseRTF();
now can deal with simplerText;
}

Now a maze game has to make a maze, so we might have something like:
class MazeGame
{
public Maze createMaze()
{
Maze aMaze = new Maze();
Room r1 = new Room( 1 );
Room r2 = new Room( 2 );
Door theDoor = new Door( r1, r2);
aMaze.addRoom( r1 );
aMaze.addRoom( r2 );
r1.setSide( North, new Wall() );
r1.setSide( East, theDoor );
r1.setSide( South, new Wall() );
r1.setSide( West, new Wall() );
r2.setSide( North, new Wall() );
r2.setSide( East, new Wall() );
r2.setSide( South, new Wall() );
r2.setSide( West, theDoor );
return aMaze;
}
}
class BombedMazeGame extends MazeGame
{
public Maze createMaze()
{
Maze aMaze = new Maze();
Room r1 = new RoomWithABomb( 1 );
Room r2 = new RoomWithABomb( 2 );
Door theDoor = new Door( r1, r2);
aMaze.addRoom( r1 );
aMaze.addRoom( r2 );
r1.setSide( North, new BombedWall() );
r1.setSide( East, theDoor );
r1.setSide( South, new BombedWall() );
r1.setSide( West, new BombedWall() );
Note the amount of cut and paste!
class MazeGame
{
public Maze makeMaze() { return new Maze(); }
public Room makeRoom(int n ) { return new Room( n ); }
public Wall makeWall() { return new Wall(); }
public Door makeDoor() { return new Door(); }
public Maze CreateMaze()
{
Maze aMaze = makeMaze();
Room r1 = makeRoom( 1 );
Room r2 = makeRoom( 2 );
Door theDoor = makeDoor( r1, r2);
aMaze.addRoom( r1 );
aMaze.addRoom( r2 );
r1.setSide( North, makeWall() );
r1.setSide( East, theDoor );
r1.setSide( South, makeWall() );
r1.setSide( West, makeWall() );
r2.setSide( North, makeWall() );
r2.setSide( East, makeWall() );
r2.setSide( South, makeWall() );
r2.setSide( West, theDoor );
return aMaze;
}
}
CreateMaze method stays the same
class BombedMazeGame extends MazeGame
{
public Room makeRoom(int n )
{
return new RoomWithABomb( n );
}
public Wall makeWall()
{
return new BombedWall();
}
abstract class MazeGame
{
public Maze makeMaze();
public Room makeRoom(int n );
public Wall makeWall();
public Door makeDoor();
class MazeGame
{
public:
virtual Maze* makeMaze() = 0;
virtual Room* makeRoom(int n ) = 0;
virtual Wall* makeWall() = 0;
virtual Door* makeDoor() = 0;
"Create objects in a separate operation so that subclasses can override the way they're created"
class Hershey
{
public Candy makeChocolateStuff( CandyType id )
{
if ( id == MarsBars ) return new MarsBars();
if ( id == M&Ms ) return new M&Ms();
if ( id == SpecialRich ) return new SpecialRich();
return new PureChocolate();
}
template <class ChocolateType>
class Hershey
{
public:
virtual Candy* makeChocolateStuff( );
}
template <class ChocolateType>
Candy* Hershey<ChocolateType>::makeChocolateStuff( )
{
return new ChocolateType;
}
Hershey<SpecialRich> theBest;
class Hershey
{
private String chocolateType;
public Hershey( String chocolate )
{
chocolateType = chocolate;
}
public Candy makeChocolateStuff( )
{
Class candyClass = Class.forName( chocolateType );
return (Candy) candyClass.newInstance();
}
Hershey theBest = new Heshsey( "SpecialRich" );
public restock()
{
blah
if ( specialRich.amount() < 10 )
{
Hershey supplier = new Hershey( "SpecialRich" );
specialRich.add( supplier.makeChocolateStuff() );
}
blah
class Room extends MapSite
{
public Room makeRoom() { return new Room(); }
etc,
}
class RoomWithBomb extends Room
{
public Room makeRoom() { return new RoomWithBomb(); }
etc,
}
etc.
class MazeGame
{
public Maze mazeMaker;
public Room roomMaker;
etc.
public MazeGame( Maze mfactory, Room rfactory, etc. )
{
mazeMaker = mfactory;
etc.
}
public Maze CreateMaze()
{
Maze aMaze = mazeMaker.makeMaze();
Room r1 = roomMaker.makeRoom( 1 );
etc.