Continuing the discussion on creational patterns, today we will introduce the Builder pattern, along with a Tree class php example.
The Builder pattern's intent is to encapsulate the details (the new operators and other wiring) of the object creation process under a common interface. Though, the Builder can actually change the internal representation of an object, as it is not a black box.
Complex object graphs which present some redundancy in construction (like Composite pattern implementations) can be simplified by factoring out most of the wiring in a Builder. In the example, a simple Tree object will be constructed by a DumbUnbalancedTreeBuilder, the ConcreteBuilder of this code sample.
The point is to abstract away the actual instantiation and to construct an interface for the building process, which is leveraged by one or more Director classes. The interface can be explicit (Builder participant) or implicitly defined by the public methods of the ConcreteBuilder. Php's duck typing supports this indirect definition of interface when needed.
Participants:
- Director: class that composes a Builder to utilize its methods to control the creation process of the Product.
- Builder: interface that presents a high-level abstraction on the actual object graph carving. GoF suggests to create a base abstract class with empty methods instead of an interface, to let the ConcreteBuilders redefine only the methods they are interested in.
- ConcreteBuilder: implementation of the Builder.
- Product: the final product of a ConcreteBuilder's work.
This is the php code sample for this pattern.
<?php /** * Tree implementation that contains one value and the references to the * left and right branches (other Tree objects). * This is our Product, which usually is not hidden with an interface * because of the very different Products that ConcreteBuilders create. */ class Tree { private $_value; private $_left; private $_right; /** * @param integer */ public function __construct($value) { $this->_value = $value; } public function getValue() { return $this->_value; } /** * @return Tree */ public function getLeft() { return $this->_left; } public function setLeft(Tree $t) { $this->_left = $t; } /** * @return Tree */ public function getRight() { return $this->_right; } public function setRight(Tree $t) { $this->_right = $t; } /** * Prints values visiting Tree with in-order traversal */ public function dump() { $string = ''; if ($this->_left) { $string .= $this->_left->dump(); } $string .= " $this->_value "; if ($this->_right) { $string .= $this->_right->dump(); } return $string; } } /** * ConcreteBuilder. You can extract an interface TreeBuilder, based on * its three public methods, if there are multiple implementations of this * participant. * This class encapsulates the necessary logic to insert new subtrees * in the right points, maintaining the ordering between values (in-order * representation). */ class DumbUnbalancedTreeBuilder { private $_tree; public function reset() { $this->_tree = null; } public function addNumber($number) { $this->_tree = $this->_addTo($this->_tree, $number); } private function _addTo(Tree $tree = null, $number) { if ($tree === null) { $tree = new Tree($number); return $tree; } if ($number < $tree->getValue()) { $tree->setLeft($this->_addTo($tree->getLeft(), $number)); } else { $tree->setRight($this->_addTo($tree->getRight(), $number)); } return $tree; } public function getTree() { return $this->_tree; } } /** * A Director might encapsulate this sample code that uses the Builder. */ $builder = new DumbUnbalancedTreeBuilder(); $builder->addNumber(7); $builder->addNumber(1); $builder->addNumber(3); $builder->addNumber(5); $builder->addNumber(8); $builder->addNumber(6); $builder->addNumber(9); $builder->addNumber(5); $builder->addNumber(4); $builder->addNumber(2); echo $builder->getTree()->dump(), "\n";There are several differences between a Builder and an AbstractFactory: AbstractFactory is a black box which returns a complete object basing on previous configuration; it preserves the contract of an AbstractProduct. A Builder allows a step-by-step construction process to take place and provides a finer control over the single collaborators management.
In the example, there is not a unique Tree in an application; an AbstractFactory would be good in returning always the same object again and again,relieving the Client class from the responsibility of choosing and configuring it. A Builder is instead good in allowing flexibility of the created object graph while hiding all unnecessary details and logic.
Nothing prevents you to reference an AbstractFactory from a Builder, that instantiates the different parts of a Product, effectively separating logic (Builder) from new operators (ConcreteFactory).
Did you like this article and the previous one? Please comment and suggest which patterns should be treated extensively in this series.
9 comments:
Nice practical example :)
I am waiting personally for the Chain Of Responsibility pattern !
Good series so far, you can really explain it well. Now I do understand were abstract factories and builders can really be used for. Often the examples in books are so abstract you can't really see a use for a certain pattern. Your series are really helpful.
What I am personally interested in is how to decide you need a certain pattern. For example why start implementing a factory method and not using the strategy pattern.
Cheers, Onno
Onno,
often patterns are recognized and harvested once an implementation has been completed. For example it's important to know what is an Abstract Factory because many times you will find yourself starting to craft a solution to the construction problem and realizing halfway that you are implementing a known, well-documented pattern.
I love the series so far! I'm following with my Head First Design Patterns book to try to really solidify the concepts in my head (the book isn't the best, but I found a cheap copy and GoF was a lot more).
I'd love to see this series followed-up with a POEAA series in the same PHP fashion!
BTW, have you read 'PHP In Action: Objects, Design, Agility' by Dagfinn Reiersol? It's a great book and is about the only other resource besides your blog that I'm found that is interested in serious and in-depth exploration of advanced OOP and OOD in PHP.
Not yet, thanks for the tip. OOP in php is an expanding field. :)
So that, what I was doing with the trees was really a pattern =D, now I know where I can improve things!
Simple Pattern , Nice :D
I have understood this pattern, but the example doesn't print the result ;) . Also I have a question. The code of directory should always encapsulate the build process, Right ? Because according do the intent of pattern the same construction process can create differents representations.
Hi Hermann, I think that Director here is just the client of the Builder implementation. Therefore it can do whatever it wants with the Builder, and of course if it can encapsulate and not expose it to other clients it's just good old information hiding.
Post a Comment