Wednesday, July 20, 2011

Builder Pattern

The builder pattern is an object creation software design pattern. The intention is to abstract steps of construction of objects so that different implementations of these steps can construct different representations of objects. Often, the builder pattern is used to build products in accordance to the composite pattern, a structural pattern.
  • Separate the specification of how to construct a complex object from the representation of the object.
  • The same construction process can create different representations.
  • Example:
    1. A converter reads files from one file format (i.e. RTF).
    2. It should write them to one of several output formats (ascii, LaTeX, HTML, etc.) 
  • No limit on the number of possible output formats.
    1. It must be easy to add a new “conversion” without modifying the code for the reader.

Requirements:
  • Single Responsibility Principle.
    1. Same reader for all output formats
    2. Output format chosen once in code
  • Open-Closed Principle.
    1. Easy to add a new output format.
    2. Addition does not change old code
  • Dynamic choice of output format.
The Problem:



Participants:
  • The reader: reads the input file, and invokes the converter to produce the output file.
  • The output file is the final product of the construction.
  • The converter is the builder that builds the final product in a complex way.

Solutions:
  • We should return a different object depending on the output format:
    1. HTMLDocument, RTFDocument, . . .
  • Separate the building of the output from reading the input
  • Write an interface for such a builder.
  • Use inheritance to write different concrete builders
UML Representation:

The Solution Code:

//Builder Interface-

class Builder {
virtual void writeChar(char c) { }
virtual void setFont(Font *f) { }
virtual void newPage() { }
};

//Here’s a concrete builder-

class HTMLBuilder : public Builder {
private:
HTMLDocument *doc;
public:
HTMLDocument *getDocument() {
return doc;
}
void writeChar(char c) {
// ...
}
void setFont(Font *f) {
// ...
}
void newPage() {
//...
}
}

The converter uses a builder-

class Converter {
void convert(Builder *b) {
while (t = read_next_token())
switch (o.kind) {
case CHAR: b->writeChar(o);
break;
case FONT: b->setFont(o);
break;
// other kinds
}
}
};

//And this is how the converter is used-
RTFBuilder *b = new RTFBuilder;
converter->convert(b);
RTFDocument *d = b->getDocument();

Comments:
  • This pattern is useful whenever the creation of an object is complex and requires many different steps.
    1. In the example, the creation of HTMLDocument is performed step by step as the tokens are read from the file.
    2. Only at the end the object is ready to be used.
  • Therefore, we separate the creation of the object from its use later on.
  • The final object is created with one single step at the end of the creation procedure.
    1. In this case, it is easier to check consistency of the creation parameters at once.
    2. example: create a Square, using the interface of a Rectangle.
       a. The user sets Height and Width in the builder, then tries to build the Square, and if they are different gets an exception telling what went wrong.

Intent:

Define an interface for creating an object, but let subclasses
decide which class to instantiate
  • Also known as Virtual Constructor.
  • The idea is to provide a virtual function to create objects of a class hierarchy.
  • each function will then know which class to instantiate.
Example:

Consider a framework for an office suite:
  • Typical classes will be Document and Application.
  • there will be different types of documents, and different types of applications.
  • for example: Excel and PowerPoint are applications, excel sheet and presentation are documents.
  • all applications derive from the same abstract class Application.
  • all documents derive from the same abstract class Document.
  • we have parallel hierarchies of classes.
  • every application must be able to create its own document object.
Example in UML


Participants:
  • Product (Document) - defines the interface of the objects the factory method creates
  • ConcreteProduct (MyDocument) - implements the Product’s interface
  • Creator (Application) - declares the factory method
  • ConcreteCreator (MyApplication) - overrides the factory method to return an instance of a ConcreteProduct
UML representation :
Collaboration:
  • 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 requ ests from the director and adds parts to the product.
  • The client retrieves the product from the builder.
Useful Tips:

  • Builder focuses on constructing a complex object step by step. Abstract Factory emphasizes a family of product objects (either simple or complex). Builder returns the product as a final step, but as far as the Abstract Factory is concerned, the product gets returned immediately.
  • Builder often builds a Composite.
  • Often, designs start out using Factory Method (less complicated, more customizable, subclasses proliferate) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, more complex) as the designer discovers where more flexibility is needed.
  • Sometimes creational patterns are complementary: Builder can use one of the other patterns to implement which components are built. Abstract Factory, Builder, and Prototype can use Singleton in their implementations.
  • Builders are good candidates for a fluent interface.
Rules of thumb:
  • Sometimes creational patterns are complementory: Builder can use one of the other patterns to implement which components get built. Abstract Factory, Builder, and Prototype can use Singleton in their implementations. [GoF, p81, 134]
  • Builder focuses on constructing a complex object step by step. Abstract Factory emphasizes a family of product objects (either simple or complex). Builder returns the product as a final step, but as far as the Abstract Factory is concerned, the product gets returned immediately. [GoF, p105]
  • Builder often builds a Composite. [GoF, p106]
  • Often, designs start out using Factory Method (less complicated, more customizable, subclasses proliferate) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, more complex) as the designer discovers where more flexibility is needed. [GoF, p136]
Sample Code :

click here to see the implementation of the builder pattern.


No comments:

Post a Comment