PHP Builder Design Pattern Part I: One Process, Many Representations

builderCover250Let’s Build Something!

A lot of the work PHP developers do involves creating the same thing with variations. For example, you may create a Web site with different organizations for desktop displays, tablet screens and mobile views. However, you want the content the same, and while set up differently, you want to have a navigation system, headers, links and all the rest that goes into a Web site. The same is true for working with MySQL, and forms of different kinds. You can create fairly complex objects, but the representations (e.g., desktop, smartphone) are different. The Builder Design pattern is a creational pattern that lets you separate the construction of complex objects from their representations so that the same construction process can create different representations. Before going further, take a look at two different results in the PlayA and PlayB buttons and download the source code:
PlayAPlayBDownload

The Simple Builder

This first example looks at creating a simple Builder pattern with all of the parts laid out and pretty spread out. Two Client objects call two different concrete builders, and while that would have been pretty easy to do with a single Client the purpose of this first example is to clearly show each of the parts. In Part II, you’ll see a more streamlined and functional version of a Builder, but for now, it’s important to see how this thing works. Before going further, take a look at the Builder class diagram in Figure 1:

Figure 1: Builder Class Diagram (with Client added)

Figure 1: Builder Class Diagram (with Client added)

As noted in Figure 1, I added the Client, and according to the Gang of Four,

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

So, the Client, while not a participant in the pattern, is clearly a key collaborator. However, I put the Client code at the end of this post because its role must be understood in the context of the Builder’s key participants.

The Builder Interface

It’s difficult to know where to begin in describing the Builder pattern; but starting with the Interface helps show the main building blocks.

<?php
//IBuilder.php
interface IBuilder
{
	public function mainHead();
	public function subHead();
	public function buildNavH();
	public function buildNavV();
	public function buildGraphic();
	public function buildVideo();
	public function buildBodyText();
}
?>

In looking at the IBuilder interface, you can see what might be the parts of a Web page. Keeping in mind that this example is a simple one, the example is a Web page “wire framer.” That is, it creates a graphic outline of what the page will look like using SVG graphics generated dynamically in the program.

The Concrete Builders

As you might imagine, there are a lot of different ways that you could create a Web page given those broad Web page elements. These first two examples use simple mobile configurations. Because the methods in IBuilder are abstract, there’s a lot of leeway in deciding what page design to use. The program displays one design that uses an image (the square with an ‘X’ in it) and one that displays the outline for a mobile site with a video (shown with a triangular ‘play’ button). They’re very similar, and as you will notice, some of the methods are only implemented by adding a pair of quotes where an argument is expected. Both concrete Builder classes can be seen in the following listing:

<?php
//BuilderA.php
class BuildMobileA implements IBuilder
{
    private $product;
 
    function __construct()
    {
        $this->product=new Product();
    }
 
    public function mainHead()
    {
        $this->product->assemble('<rect x="0" y="0" width="200" height="30" fill="#000099" stroke="#cc0000" stroke-width="2"  />');
    }
    public function subHead()
    {
        $this->product->assemble('<rect x="0" y="35" width="150" height="20" fill="#cc0000" stroke="#00cc00" stroke-width="2"  />');
    }
    public function buildNavH()
    {
        $this->product->assemble('<circle cx="65" cy="65" r="4" stroke="none" stroke-width="0" fill="#00cc00" /><circle cx="75" cy="65" r="4" stroke="none" stroke-width="0" fill="#00cc00" /><circle cx="85" cy="65" r="4" stroke="none" stroke-width="0" fill="#00cc00" /><circle cx="95" cy="65" r="4" stroke="none" stroke-width="0" fill="#00cc00" /><circle cx="105" cy="65" r="4" stroke="none" stroke-width="0" fill="#00cc00" />');
    }
    public function buildNavV()
    {
        $this->product->assemble("");
    }
    public function buildGraphic()
    {
        $this->product->assemble('<rect x="0" y="75" width="200" height="200" fill="none" stroke="#cc0000" stroke-width="2"  /> <g stroke="#cc0000"> <line x1="0" y1="75" x2="200" y2="275" stroke-width="2"  /><line x1="200" y1="75" x2="0" y2="275" stroke-width="2"  /></g>');
    }
    public function buildVideo()
    {
        $this->product->assemble("");
    }
    public function buildBodyText()
    {
        $this->product->assemble('<g stroke="#5a5a5a">
<line x1="10" y1="290" x2="190" y2="290" stroke-width="1" /> <line x1="10" y1="300" x2="190" y2="300" stroke-width="1" /> <line x1="10" y1="310" x2="190" y2="310" stroke-width="1" /></g>');
    }
    public function getResult()
    {
        return $this->product;   
    }    
}
 
?>
 
//--------------------
 
<?php
//BuilderB.php
class BuildMobileB implements IBuilder
{
    private $product;
 
    function __construct()
    {
        $this->product=new Product();
    }
 
    public function mainHead()
    {
        $this->product->assemble('<rect x="0" y="0" width="200" height="30" fill="#468966" stroke="none" stroke-width="none"  />');
    }
    public function subHead()
    {
        $this->product->assemble('<rect x="0" y="35" width="150" height="20" fill="#b64926" stroke="none" stroke-width="none"  />');
    }
    public function buildNavH()
    {
        $this->product->assemble("");
    }
    public function buildNavV()
    {
        $this->product->assemble('<rect x="0" y="57" width="200" height="15" rx="15" fill="#ffb03b" stroke="none" stroke-width="none"  /> ');
    }
    public function buildGraphic()
    {
        $this->product->assemble("");
    }
    public function buildVideo()
    {
        $this->product->assemble('<rect x="0" y="75" width="200" height="150" fill="none" stroke="#8e2800" stroke-width="2"  /> <circle cx="94" cy="146" r="20" fill="#fff0a5" stroke="none" stroke-width="none"  /> <path d="M 90 130 L 110 145 L 90 160 z" fill="#8e2800" stroke="none" stroke-width="none" />');
    }
    public function buildBodyText()
    {
        $this->product->assemble('<g stroke="#5a5a5a">
<line x1="10" y1="235" x2="190" y2="235" stroke-width="1" /> <line x1="10" y1="245" x2="190" y2="245" stroke-width="1" /> <line x1="10" y1="255" x2="190" y2="255" stroke-width="1" /></g>');
    }
    public function getResult()
    {
        return $this->product;   
    }    
}
 
?>

The implementation generates two different representations of the same set of methods. Each one is then compiled in a single Product, and the Product does the display work. Note that all of the methods call a Product assemble() method. The assemble() method pushes the data into an array in the Product object. Before examining the Product class, there’s another key participant of the pattern that must be seen first.

The Director

The Director acts almost like a Template Method. It sets the order in which the methods in the Builder object are called. In the class diagram you can see that iteration through the concrete Builder objects in the Director does the work, but in this first example, I placed them so that the Director role is a bit clearer.

<?php
//Director.php
class Director
{
    private $builder;
    public function doBuild(IBuilder $buildNow)
    {
        $this->builder=$buildNow;
        $this->builder->mainHead();
	$this->builder->subHead();
        $this->builder->buildNavH();
	$this->builder->buildNavV();
	$this->builder->buildGraphic();
        $this->builder->buildVideo();
        $this->builder->buildBodyText();
    }
}
?>

There’s no reason that the same method cannot be called more than once (to place a background block at the top and the bottom, for example), but in order to keep it clear, it just calls each method once.

The Product

Indirectly, you can see one of the very cool features of the Builder pattern in the Product class. You can have as many different concrete builders as you want, and they’re all handled by a single Product class. In other words, you don’t need separate products for the different representations generated by the different concrete builders.

<?php
//Product.php
class Product
{
    private $parts;
    public function __construct()
    {
        $this->parts=array();
    }
 
    public function assemble($segment)
    {
        array_push($this->parts,$segment);
    }
 
    public function display()
    {
        echo '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="800" height="600">';
        foreach($this->parts as $piece)
        {
            echo $piece;
        }
        echo "</svg>";
        unset($piece);
    }
}
?>

The Product takes care of packaging all of the data sent from the concrete Builders and processing it in any way the developer needs. The best part is that it is done in a single class.

The Client

Now (finally), we can look at the Client. As noted, while not a participant in the Builder design pattern, the Client plays a crucial collaboration role. It specifies which product it wants built. In this first example ClientA and ClientB build different products by calling different concrete builders. The following listing shows how the requests are made:

<?php
//ClientA.php
ERROR_REPORTING( E_ALL | E_STRICT );
ini_set("display_errors", 1);
function __autoload($class_name) 
{
    include $class_name . '.php';
}
class ClientA
{
    private $director;
    private $mobile;
    private $productNow;
    public function __construct()
    {
        $this->mobile=new BuildMobileA();
        $this->director=new Director();
        $this->goMobile();
    }
 
    private function goMobile()
    {  
        $this->director->doBuild($this->mobile);
        $this->productNow=$this->mobile->getResult();
        $this->productNow->display();
    }
}
$worker=new ClientA();
?>

A request to build BuildMobileB is identical except the request specifies BuildMobileB instead of BuildMobileA.

An Easy Flexible Pattern

In Part II of the Builder series, I’d like to use a similar Builder to generate actual Web pages. Also, I’d like to look at how the Director can iterate through an object to pull out each method and fire it rather than using list of methods. For me, the Director looks a lot like a Template Method, and if set up with a looping iteration, it would be even more so. As always, I welcome any and all comments.

Share

Copyright © 2013 William Sanders. All Rights Reserved.

2 Responses to “PHP Builder Design Pattern Part I: One Process, Many Representations”


  • Hi Bill,

    thank you again for great tutorials of Design Patterns they are very helpful. Only thing about current Builder pattern I want to ask is:

    Why you create new instance of “Product” in ClientA constructor? Product is instanced automatically in “BuildMobileA” and as this is private property you know that only with Product instance you are always able to work. Also in “goMobile” you reassign “productNow” so the first instance in useless.

    Please correct me if I’m wrong or overlooked something important.

    Thanks,
    George

  • Hi George,

    You are absolutely right. During the initial testing and development I put in that line to create a new Product instance, but it was overridden in the goMobile() method and so the redundancy went unnoticed.

    Thanks for your sharp eye! It’s all fixed now.

    Kindest regards,
    Bill

Leave a Reply