CS 635: Advanced Object-Oriented Design & Programming |
---|
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 |
Product Trader, by Baumer & Riehle in Pattern Languages of Program Design 3, Eds Martin, Riehle, Buschman, 1998, pp 29-46.
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 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 } }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(); }
Decouples the client from the product which eases the adaptation, configuration, and evolution of class hierarchies, frameworks, and applications
Products can be configured for specific domains
Product class hierarchies can be evolved easily
New product classes can be introduced easily
Special constructor parameters require overhead
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; } }
Some objects can recreate themselves from this string
To recreate the objects one needs the full class name for the object
Some times the full class name may not be available
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!
// 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; } }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(); } } }
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(); } } }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); }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 ); } }