Builder Pattern

  Home

Description

This pattern could be described as a way of building complex objects which share common elements.

Example

Let's say we have documents that we want to provide to our clients in whatever format they require. Some clients want Word format, some want PDF, some want HTML and some want XML. We also know that in the future more formats will be required. Our documents can be broken down into elements such as document header, page header, margin width, pre-data descriptive text, data, post-data descriptive text, etc. The builder pattern is perfect to handle this. First make sure you are familiar with the abstract factory pattern I described yesterday. Builder has many similarities to abstract factory. The main difference being that the "factories" or "toolkits" created by the abstract factory are now called "builders" and instead of providing objects for a particular domain they provide methods to build the various parts of a single complex object. We start with an AbstractBuilder class which contains a static (shared in VB) factory method to create the builder objects that will build the documents in the various formats. It also contains abstract methods to build the various parts of the formatted document and finally a property for returning the finished document in the required format. The different document classes must use a common interface so the client code can handle them without knowing what class they are, so the property returns a type of that interface.

Public MustInherit Class AbstractDocumentBuilder
    Public Shared Function GetBuilder(format As String) As AbstractDocumentBuilder
        Select Case format.ToUpper()
            Case "WORD"
                Return New WordBuilder
            Case "PDF"
                Return New PDFBuilder
            Case "XML"
                Return New XMLBuilder
            Case Else
                Return Nothing
        End Select
    End Function
 
    Public MustOverride Sub BuildDocHeader(docHeaderText As String)
    Public MustOverride Sub BuildPageHeader(pageHeaderText As String)
    Public MustOverride Sub BuildPreDataText(preDataText As String)
    'more methods for other parts of the document ...
 
    Public MustOverride ReadOnly Property Document() As IDocument
End Class
Note: You could give these part builder methods "do nothing" implementations so there would be no need to implement them for formats that don't have that part. Next are the concrete builder classes for the formats:

Public Class WordBuilder : Inherits AbstractDocumentBuilder
    Private _document As New WordDocument
 
    Public Overrides ReadOnly Property Document() As IDocument
        Get
            Return _document
        End Get
    End Property
 
    Public Overrides Sub BuildDocHeader(docHeaderText As String)
        'code here for Word format
    End Sub
 
    Public Overrides Sub BuildPageHeader(pageHeaderText As String)
        'code here for Word format
    End Sub
 
    Public Overrides Sub BuildPreDataText(preDataText As String)
        'code here for Word format
    End Sub
End Class
In my example the IDocument interface contains a method to write the document to a file. You could give it whatever methods are appropriate for your implementation. For example you could give it a "Send()" method so it emails itself to the person requesting it.

Public Interface IDocument
    Sub Write(fout As FileStream)
End Interface
Next is the class representing the formatted document:

Public Class WordDocument : Implements IDocument
    Public Sub Write(ByVal fout As FileStream) Implements IDocument.Write
        'code to write the document to the stream
    End Sub
 
    'other needed methods & properties
End Class
Finally the client would contain code something like this (note: "doc" represents the original unformatted document):

Public Sub WriteDocument(format As String, fout As FileStream)
    Dim finalDocument As IDocument
    Dim builder As AbstractDocumentBuilder
    builder = AbstractDocumentBuilder.GetBuilder(format)
    builder.BuildDocHeader(doc.DocumentHeader)
    builder.BuildPageHeader(doc.PageHeader)
    builder.BuildPreDataText(doc.PreDataText)
    'Build other parts of the document ...
 
    finalDocument = builder.Document
    finalDocument.Write(fout)
End Sub
To add a new format you create the builder class for it and add a 'Case "NEWDOC"' to the Select statement in the abstract builder class.

Resources

Data & Object Factory: Builder

Wikipedia - Builder Pattern

DotNetExtreme - Builder Pattern