SDSU CS 635: Advanced Object-Oriented Design & Programming
Spring Semester, 1998
Builder and Product Trader

To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98

Contents of Doc 14, Builder and Product Trader


References slide # 1
Builder slide # 2
...Intent slide # 2
...Applicability slide # 2
...Collaborations slide # 3
...Example - RTF Converter slide # 4
...Consequences slide # 9
Product Trader slide # 10
...Intent slide # 10
...Structure slide # 10
...Applicability slide # 11
...Consequences slide # 12
...Implementation slide # 13
...Example slide # 16


References

Design Patterns: Elements of Reusable Object-Oriented Software, Gamma, Helm, Johnson, Vlissides, Addison Wesley, 1995, pp 97-105

Product Trader, by Baumer & Riehle in Pattern Languages of Program Design 3, Eds Martin, Riehle, Buschman, 1998, pp 29-46.


Doc 14, Builder and Product Trader Slide # 2

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 14, Builder and Product Trader Slide # 3

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 14, Builder and Product Trader Slide # 4

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 14, Builder and Product Trader Slide # 5
RTF for Slide # 2 of this Document

{\header\pard\plain\s1\s2\tqr\tx8640\f3\fs24\f2\fs24\f2\fs24 March 9, 1998\tab Doc 14 Builder and Product Trader 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 14, Builder and Product Trader Slide # 6
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 14, Builder and Product Trader Slide # 7
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 getText()
          {
          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 getText()          { return the correct thing }
     }


Doc 14, Builder and Product Trader Slide # 8
Main Program

main()
     {
     ASCII_Converter simplerText = new ASCII_Converter();
     String rtfText;

     // read a file of rtf into rtfText

     RTF_Reader myReader = 
          new RTF_Reader( simplerText, rtfText );

     myReader.parseRTF();

     String myProduct = simplerText.getText();
     }

Doc 14, Builder and Product Trader Slide # 9

Consequences



Implementation



Doc 14, Builder and Product Trader Slide # 10

Product Trader

Intent


Allows clients to create objects by naming an interface and by providing a specification

Decouples the client from the product which eases the adaptation, configuration, and evolution of class hierarchies, frameworks, and applications

Structure


Product Trader Structure


Doc 14, Builder and Product Trader Slide # 11

Applicability


Use a product trader if you want:


Do not use a product trader as a replacement or factory methods or direct object creation


Doc 14, Builder and Product Trader Slide # 12

Consequences

Advantages

Clients become independent of concrete product classes

Clients just know about specification

Product classes are determined at run time

Products can be configured for specific domains

Product class hierarchies can be evolved easily

New product classes can be introduced easily

Disadvantages

Increased control and dependency complexity

Selecting a product is now a run time selection with no compile-time checking.

Need for advanced configuration mechanisms

Since classes are selected at run time a linker may not realize a class needs to be linked with the program

Ambiguous specifications

Special constructor parameters require overhead

Special work is required to provide a concrete product class with a special parameter in its constructor

Doc 14, Builder and Product Trader Slide # 13

Implementation

Implementing the mapping from specification to create


Implementing creators

Avoid creating a creator class for every product class


Doc 14, Builder and Product Trader Slide # 14
Sample C++ template class for creator object

template<class ProductType, class SpecType>
class Creator
     {
     public:
          Creator(SpecType aSpec) : _aSpecification(aSpec) {}

          SpecType getSpecification() 
               { 
               return _aSpecification; 
               }

          ProductType* create() = 0;

     private:
          SpecType _aSpecification;
     };

template<class ProductType, class ConcreteProductType, 
                    class SpecType>
class ConcreteCreator : public Creator<ProductType,
SpecType>
     {
     public:
          ConcreteCreator( SpecType aSpec) : 
               Creator<ProductType, SpecType> ( aSpec ) 
               {}

          ProductType* create() 
               { 
               return new ConcreteProductType; 
               }
     }

Why use two classes?
Doc 14, Builder and Product Trader Slide # 15
Implementation Continued
Implementation Specifications

Use built-in value types: ints, strings, etc

Use explicit specification objects

Provides more reusability


Doc 14, Builder and Product Trader Slide # 16

Example

Situation

In Java objects can create a string representation of themselves

Some objects can recreate themselves from this string

java.util.Properties
java.lang.String
sdsu.util.Table
sdsu.util.LabeledTable
sdsu.util.List
sdsu.util.LabeledData
any class implementing the interface sdsu.util.Stringizable

It is useful to transport or store the objects in this string form

To recreate the objects one needs the full class name for the object

Some times the full class name may not be available

The string may be created by a human

The process used to recreate objects differs among the classes


Doc 14, Builder and Product Trader Slide # 17
Problem

How to read a class name and the string from a file or stream and recreate the correct object?

Do not what to use if statements on the class name as the if statement is needed in several different locations

Tried isolating the if statement in separate class, which would be used whenever one needed to create such an object

But there arose another place where the if statement was needed!

A solution

Use ProductTrader

Doc 14, Builder and Product Trader Slide # 18
Java Solution Code

// Exception used by creators

public class CreationException extends Exception
     {
     public CreationException()  { super(); }

     public CreationException(String s)  { super(s); }
     }

Creator Classes
public interface Creator
     {
     public Object create( String objectState ) 
          throws CreationException;
     }

public class StringCreator implements Creator
     {
     public Object create( String objectState ) 
          {
          return objectState;
          }
     }


Doc 14, Builder and Product Trader Slide # 19
Creator Classes Continued
 

public class PropertyCreator implements Creator
     {
     public Object create( String objectState ) 
          throws CreationException
          {
          try
               {
               Properties dataObject = new Properties();
               InputStream in = 
                         new StringBufferInputStream( objectState);
                         
               dataObject.load( in );
               return dataObject;
               }
          catch (IOException error )
               {
               throw new CreationException();
               }
          }
     }


Doc 14, Builder and Product Trader Slide # 20
Creator Classes Continued

public class StringizableCreator implements Creator
     {
     String fullClassName;
     
     public StringizableCreator( String classSpecification )
          {
          fullClassName = classSpecification;
          }
          
     public Object create( String objectState )  
          throws CreationException
          {
          try
               {
               Stringizable product = (Stringizable)
                     Class.forName( fullClassName ).newInstance();
               product.fromString( objectState);
               return product;
               }
          catch (Exception creationError )
               {
               throw new CreationException();
               }
          }
     }

Doc 14, Builder and Product Trader Slide # 21
Trader Product Class

public class StringToObjectTrader
     {
     Hashtable creators = new Hashtable();
     
     public static StringToObjectTrader standard()
          {
          StringToObjectTrader standardSetting = 
                    new StringToObjectTrader();
          standardSetting.add( "String", new StringCreator() );
          standardSetting.add( "java.lang.String", new StringCreator() );
          standardSetting.add( "Properties", new PropertyCreator() );
          standardSetting.add( "java.util.Properties", new PropertyCreator() );
          standardSetting.add( "Table", new StringizableCreator( "sdsu.util.Table") );
          standardSetting.add( "sdsu.util.Table", 
                                             new StringizableCreator( "sdsu.util.Table") );
          standardSetting.add( "LabeledTable", 
                                             new StringizableCreator( "sdsu.util.LabeledTable") );
          standardSetting.add( "sdsu.util.LabeledTable", 
                                             new StringizableCreator( "sdsu.util.LabeledTable") );
          standardSetting.add( "LabeledData", 
                                             new StringizableCreator( "sdsu.util.LabeledData") );
          standardSetting.add( "sdsu.util.LabeledData", 
                                             new StringizableCreator( "sdsu.util.LabeledData") );

          standardSetting.add( "List", new StringizableCreator( "sdsu.util.List") );
          standardSetting.add( "sdsu.util.List", new StringizableCreator( "sdsu.util.List") );

          return standardSetting;
          }
          
     public void add( String specification, Creator aCreator)
          {
          creators.put( specification, aCreator);
          }
     

Doc 14, Builder and Product Trader Slide # 22
Trader Product Class Continued
 

     public void remove( String specification )
          {
          creators.remove( specification);
          }

     public boolean contains( String specification )
          {
          return creators.containsKey( specification );
          }
          
     public Object create( String specification, String objectData ) 
               throws CreationException
          {
          Creator aCreator;
          if ( contains( specification ) )
               aCreator = (Creator) creators.get( specification );
          else 
               // assume is Stringizable
               aCreator = new StringizableCreator( specification );

          return aCreator.create( objectData );
          }
     }

visitors since 10-Mar-98