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 Outline
abstract 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.