SDSU CS 696: Advanced OO
Spring Semester, 1997
Doc 11 Builder and Factory Method

To Lecture Notes Index
San Diego State University -- This page last updated Mar 18, 1997
----------

Contents of Doc 11 Builder and Factory Method


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


Doc 11 Builder and Factory Method Slide # 1

Builder

Intent


Separate the construction of a complex object from its representation so that the same construction process can create different representations

Applicability


Use the Builder pattern when



Doc 11 Builder and Factory Method Slide # 2

Collaborations


The client creates the Director object and configures it with the desired Builder object

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




Doc 11 Builder and Factory Method Slide # 3

Example - RTF Converter


A word processing document has complex structure:

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:

TeX, html, ascii, etc.


Doc 11 Builder and Factory Method Slide # 4
RTF for Slide # 1 of this Document

{\header\pard\plain\s1\s2\tqr\tx8640\f3\fs24\f2\fs24\f2\fs24 March 13, 1997\tab Doc 11 Builder slide # \chpgn\par}\fs36\f14\f2\fs24\f2\fs24\f14\fs36{\b Builder}
\par{\b Intent}
\par\ql
\par Separate the construction of a complex object from its representation so that the same construction process can create different representations
\par
\par\qc{\b Applicability}
\par\ql
\par Use the Builder pattern when
\par
\par\li720\ri0\'a5 the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled
\par\li0
\par\li720\ri0\'a5 the construction process must allow different representations for the object that's constructed
\par\li0


Doc 11 Builder and Factory Method Slide # 5
Outline of Solution Using Builder

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.
                    }
               }
          }
     }
     
     
Doc 11 Builder and Factory Method Slide # 6
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 }
     }


Doc 11 Builder and Factory Method Slide # 7
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;
     }

Doc 11 Builder and Factory Method Slide # 8

Consequences



Implementation



Doc 11 Builder and Factory Method Slide # 9

Factory Method

Example - Maze Game


Classes for Mazes

Now a maze game has to make a maze, so we might have something like:


Doc 11 Builder and Factory Method Slide # 10

Maze Class Version 1

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;
          }
     }



Doc 11 Builder and Factory Method Slide # 11
How do we make Other Mazes?
Idea 1 - Subclass MazeGame, override createMaze




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() );

etc.

Note the amount of cut and paste!


Doc 11 Builder and Factory Method Slide # 12
How do we make Other Mazes?
Idea 2 - Factory Method
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;
          }
     }

Doc 11 Builder and Factory Method Slide # 13
Now subclass MazeGame override make methods

CreateMaze method stays the same


class BombedMazeGame extends MazeGame
     {
     
     public Room makeRoom(int n ) 
          { 
          return new RoomWithABomb( n ); 
          }

     public Wall makeWall() 
          { 
          return new BombedWall(); 
          }


Doc 11 Builder and Factory Method Slide # 14

Implementation


Top level Factory method is in an abstract class

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;

Top level Factory method is in a concrete class

"Create objects in a separate operation so that subclasses can override the way they're created"


Doc 11 Builder and Factory Method Slide # 15

Parameterized Factory Methods


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();
          }

C++ Templates to Avoid Subclassing


template <class ChocolateType>
class Hershey 
     {
     public:
          virtual Candy* makeChocolateStuff( );
     }

template <class ChocolateType>
Candy* Hershey<ChocolateType>::makeChocolateStuff( )
     {
     return new ChocolateType;
     }

Hershey<SpecialRich> theBest;

Doc 11 Builder and Factory Method Slide # 16

Java forName and Factory methods


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" );


Doc 11 Builder and Factory Method Slide # 17

Clients Can Use Factory Methods


class CandyStore
{

public restock()
{
blah

if ( specialRich.amount() < 10 )
{
Hershey supplier = new Hershey( "SpecialRich" );
specialRich.add( supplier.makeChocolateStuff() );
}

blah


Doc 11 Builder and Factory Method Slide # 18
How do we make Other Mazes?
Idea 3 - Factory Method in Client or is that Prototype?

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.




----------