Getting the Director Right
Part I of the Builder two-part series explains the Builder pattern and provides a simple example. Back in early 2009, I had used a similar example in ActionScript 2.0 that performed a similar task; namely building different Web pages from a single Builder pattern. (If you experienced déjà vu, it may be that you came across that earlier post.) At the time I added all of the necessary participants, but I really was not too concerned with certain details because the goal focused more on getting the participants to perform their tasks correctly than on some of the details. In Part I, the PHP example paid closer attention to details, but again, the focus was on exposition more than detailed features.

Figure 1: Director details in Builder class diagram.
Upon closer examination of the examples shown in the original Design Patterns: Elements of Reusable Object-Oriented Software, I realized that two different examples illustrated the Builder. The first one is an RTF Reader and the second is based on a Maze example from an earlier chapter. I had been digging through the code in the maze example without much luck. In the pseudocode notation of the RTF Reader, however, it shows a while loop used in conjunction with a switch statement. I tried writing similar code in PHP, and it worked like a champ, but it was not very reusable. (I rarely imply that GoF might have done something less than perfect!) So I went to work using the more abstract pseudocode notation in the structural class diagram. However, before getting into that, go ahead and test the application with the Play buttons and download all of the code.
Iterating Through an Object in PHP
All I needed to do was to create a simple loop that would iterate through an object. Originally, I thought that I’d need to use an object created by implementing a concrete Builder. However, in looking closely at the Builder class diagram, you can see that the Builder interface does not include a getResult() method. That method is only in the concrete Builder to get the assembled Product. Also, I found that I got a constructor function (__construct()) if I used a concrete Builder as a target object. So why not use the interface as the object? Figure 2 shows the general method for finding the methods in a class, and it works for interfaces as well.

Figure 2: Getting methods from classes and interfaces
So far so good. Now I have an object with all of the method names in string format. As you may know, PHP allows you to use strings to create variables, but you can also dynamically generate usable methods using variable functions. Figure 3 shows the format with an example of how to do it with a string stored in a PHP variable.

Figure 3: Using a string value to call a class method
The trickiest part for me was remembering to place a ‘$’ in front of the method. However, once I got used to that idea, the rest was a matter of iterating through the object containing the methods and placing them on a concrete Builder instance. As you can see in the following listing the Director class is now much more re-usable:
//Director.php
class Director
{
private $builder;
private $builder_methods;
public function doBuild(IBuilder $buildNow)
{
$this->builder=$buildNow;
$this->builder_methods=get_class_methods('IBuilder');
foreach($this->builder_methods as $part)
{
$this->builder->$part();
}
}
}
?>
|
Given this format, you can use the identical Director for any PHP Builder application you might create. The only change would be the name of the interface from IBuilder to whatever name you want to use. It pulls out all of the abstract method names from the interface and then assigns then to whatever concrete Builder instance is passed to it. It does not matter how they’re implemented as long as they adhere to the structure. However, you may also create different Directors using the same Builder interface by ordering the building blocks in a different way. (More on this later.)
New Interface and Concrete Builders
Now that the Director has been boiled down to an essential method for generating the necessary parts, we should be able to create a different interface and concrete builders and still have a way to encapsulate the building process and keep it hidden from the Client(s). So, using the same programming model described in Part I, take a look at a revised interface and concrete builders:
The interface has been cut down to only three methods. The buildMedia() method suggests different types of media, and the examples in the concrete builders provide one for graphics and one for video. They are simple, but if more complexity is required, adding more methods is simple enough.
//IBuilder.php
interface IBuilder
{
public function buildHead();
public function buildMedia();
public function buildCaption();
}
?>
|
Two classes (the concrete builders) implement the IBuilder interface. They each implement the interface differently but follow the correct signatures.
//BuildPix.php
class BuildPix implements IBuilder
{
private $product;
function __construct()
{
$this->product=new Product();
}
public function buildHead()
{
$this->product->assemble('
|
As you can see, both concrete builders use HTML elements and attributes to build the functional requirements for placing and labeling their respective media. These builders can be changed without making any other changes in the program. More importantLY, the changes occur without negatively affecting or breaking other parts of the program. In a simple program that’s usually not a problem, but in more complex program, the problems grow exponentially without design patterns. (Building a house of cards comes to mind.) However, using the Builder pattern, the encapsulated participants and interaction allows change and experimentation in even the most complex creational program.
The New Product
The Product is still adding the top and bottom of an HTML5 page, and the $parts array (assembled by the chosen concrete Builder) are used to fill in the the body contents.
//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 '
|
This function and structure of the Product is much like the one used in Part I of this PHP Builder series. However, the Product could be all different kinds of built objects other than Web pages.
The Two Clients
The two Client classes assemble a request, and as you can see, the only difference between the two clients is that each requests a different concrete builder:
$this->media=new BuildPix();
and
$this->media=new BuildVid();
It would be a simple enough matter to create an HTML UI where the user chooses the the concrete builder and passes the choice on to a single Client to process a selected concrete builder. However, here, the Clients represent a single choice even though the requests are configured the same.
//ClientPix.php
ERROR_REPORTING( E_ALL | E_STRICT );
ini_set("display_errors", 1);
function __autoload($class_name)
{
include $class_name . '.php';
}
class ClientPix
{
private $director;
private $media;
private $productNow;
public function __construct()
{
$this->media=new BuildPix();
$this->director=new Director();
$this->goMedia();
}
private function goMedia()
{
$this->director->doBuild($this->media);
$this->productNow=$this->media->getResult();
$this->productNow->display();
}
}
$worker=new ClientPix();
?>
//
?php
//ClientVideo.php
ERROR_REPORTING( E_ALL | E_STRICT );
ini_set("display_errors", 1);
function __autoload($class_name)
{
include $class_name . '.php';
}
class ClientVideo
{
private $director;
private $media;
private $productNow;
public function __construct()
{
$this->media=new BuildVid();
$this->director=new Director();
$this->goMedia();
}
private function goMedia()
{
$this->director->doBuild($this->media);
$this->productNow=$this->media->getResult();
$this->productNow->display();
}
}
$worker=new ClientVideo();
?>
|
The Gang of Four make it clear that
The client creates the Director object and configures it with the desired Builder object. (p. 99)
Likewise Gamma et al point out,
The client retrieves the product from the builder.
Given these roles, I have never quite figured out why the Client is not considered an integral participant in the Builder design pattern, but it is clearly an important collaborator. In any case keep in mind the key roles it plays in the Builder design pattern.
The Flexible Director
The two Director examples in this series represent fairly simple roles for the Director. However, the Director (as the name implies) can do more than assemble the parts in a single sequence. It can reconfigure the parts in any way you want. The Gang of Four point out,
“The code is written once; then different Directors can reuse it to build Product variants from the same set of parts.
Given the possibilities of what the Director can do, its role is far more than a tool for a single assembly of the parts created by iterating through a single set of methods defined by the interface. It can re-arrange the sequence in the interface and build many different kinds of products (Product variants).
On the Web you may find pronouncements that you really don’t need a Director in the Builder pattern, and you can make-do with a Client that configures the parts, including the sequence in building the Product. Of course that’s possible, but I’d question the wisdom of that course of action. It effectively binds the Client and Director objects in ways that limit both in a tight binding and flexibility. Keeping in mind the Single Responsibility Rule in OOP, I’d much prefer to give the Client its responsibility and the Director its. Then, when you want to get creative with the Director, your code is not bound up in the Client. So, if someone tells you, You really don’t need a Director in a Builder pattern. Don’t believe them. (Who do they think they’re trying to fool?)
Copyright © 2013 William Sanders. All Rights Reserved.
I don’t understand the significance or necessity of the following line:
$this->productNow=new Product();
in Client’s __constructor method.
The newly created product is not used anywhere and is overwritten in goMedia() with :
$this->productNow = $this->media->getResult();
Am i missing something?
Hi Konstantin,
Thank you! During development I had accidentally left in the line:
$this->productNow = new Product();
and I forgot to take them out (of both clients) when I realized they did not belong. However, because, the functionality was the same, it was easy to forget. I have now updated the form and the unnecessary line is now removed from both clients.
Vriendelijke groeten,
Bill
Hi. I build a store where the query is build dynamic as with a faceted search. Will this pattern work better than composite or filter pattern?
category=shirts&color=red&size=xl
category=shirts&color=red
category=shirts
But what if I want to restrict certain attributes to a specific category? For example shirts may have color and size, where “bags” may have only color. Is the case for the decorator pattern? Or is a combination of patterns? I appreciate your input. Great blog!
Hi Vincent,
I’m not sure whether the Builder is the best design pattern for what you want to do. If you want a pattern to have different properties but want to use the same core, have you looked at the Decorator pattern? The example used in the Decorator looks to be more of what you want than the Builder.
Kindest regards,
Bill