The Builder Pattern

The Builder Pattern

If you look back at the composite pattern, you'll notice that the objects that made up the composite were manually created, as shown in the following example:

   $drums = new DrumSet("tama maple set");    $drums->add(new SnareDrum("snare drum"));    $drums->add(new BaseDrum("large bass drum"));    $cymbals = new Cymbal("zildjian cymbal set");    $cymbals->add(new Cymbal("small crash"));    $cymbals->add(new Cymbal("large high hat"));    $drums->add($cymbals); 

The code creating this DrumSet composite is not particularly complex, but what if you needed to create Instrument or Instrument composite objects for many different Musician objects, and those Musician objects in turn were composites of a Band object?

It wouldn't be impossible to write out the code that created the new objects and then added them, although it might start to get tedious if you had several bands with several musicians in them, each with their own set of instruments. If you needed to create bands in response to the actions of a user, perhaps through a GUI, then it might start to get difficult especially if you had to hard code each type of band, with the required musicians and instruments.

Implementation

Say that you were required to create a wizard that generated a Band for an end user. The user would choose from a list of genres (for example, rock, country, salsa, heavy metal, and so on), and the resulting Band would be returned, assembled with its musicians and their instruments. Figure 4-13 shows the class diagram for the builder pattern.


Figure 4-13

For this example, the Builder pattern creates Bands that have only two types of Musicians, guitarists and drummers.

   <?php    interface Builder {        public function buildDrummer();        public function buildGuitarist();    }    ?> 

Each time a concrete builder class is instantiated, it creates a Band object. Take a look at the code for the RockBandBuilder class that follows.

   <?php    require_once("interface_builder.php");    require_once("class_rockband.php");    require_once("class_musician.php");    require_once("class_instrument.php");    class RockBandBuilder implements Builder {      private $band;      function __construct($name) {             $this->band = new RockBand($name);      }      public function getBand() {             return $this->band;      }      public function buildDrummer() {             $musician = new Musician("rock drummer");             $drumset = new Instrument("rock drum kit");             $drumset->add(new Instrument("cymbal"));             $drumset->add(new Instrument("bass drum"));             $drumset->add(new Instrument("snare drum"));             $musician->addInstrument($drumset);             $this->band->addMusician($musician);      }      public function buildGuitarist() {             $musician = new Musician("rock guitarist");             $guitar = new Instrument("electric guitar");             $musician->addInstrument($guitar);             $this->band->addMusician($musician);      }    }    ?> 

See how the implementation of the constructor in RockBandBuilder creates a RockBand? Similarly, the constructor of CountryBandBuilder creates a CountryBand, shown next, in the file countryband_builder.php.

   <?php    require_once("interface_builder.php");    require_once("class_musician.php");    require_once("class_countryband.php");    require_once("class_instrument.php");    class CountryBandBuilder implements Builder {      rivate $band;      function __construct() {             $this->band = new CountryBand();      }      public function getBand() {             return $this->band;      }      public function buildDrummer() {             $musician = new Musician("washboard player");             $drumset = new Instrument("washboard");             $musician->addInstrument($drumset);             $this->band->addMusician($musician);      }      public function buildGuitarist() {             $musician = new Musician("country guitarist");             $guitar = new Instrument("acoustic guitar");             $musician->addInstrument($guitar);             $this->band->addMusician($musician);      }    }    ?> 

Check out the buildDrummer() method from RockBandBuilder. Now compare it to the one from CountryBandBuilder. Notice how each method creates not only the Musician object but also the instruments for that musician. Because of the Builder interface, both Builders are required to implement the buildDrummer() and buildGuitarist() methods, but they each construct a Musician in a completely different way, including the Instrument objects belonging to that musician.

You may have noticed that the Musician and Instrument classes are no longer subclassed into specific subtypes such as Guitarist. We did this to demonstrate that Builders can be implemented to create different objects as in the constructor or the same objects with different parameters and operations, as in the buildDrummer() method.

The Director

Builder patterns have one final important aspect, called the Director. The Director is responsible for calling the methods of the Builder to create the finished product, which in this case is a Band object. In this example, the Director will be the Application object similar to the one described in the facade pattern. The Application class follows in a file called application.php:

   <?php    class Application {      public static function createBand(Builder $builder) {             $builder->buildGuitarist();             $builder->buildDrummer();             return $builder->getBand();      }    }    ?> 

The Application class has one method, createBand, which takes a Builder as its argument. The Application then calls the create methods of the passed Builder object. You should note two important points here. First, the Application decides which methods of the Builder it wants to call; second, it doesn't care which type of Builder is passed to it.

Finally, here is how you would use the Application (a.k.a. the Director) and Builder together. Simply create an instance of the appropriate Builder object and pass it to the createBand method of the Application.

   $builder = new RockBandBuilder();    $band = Application::createBand($builder); 

The Application object and Builder work together to build the correct Band object step by step. The Band object is manipulated and stored in the Builder until it's requested by the getBand method.

Considerations

The builder pattern is useful for assembling composites and hierarchical object structures like the Band->Musician->Instrument one. Although having the Builder return a completed object is useful, don't forget that the Band object returned by the Builder is still the same as any Band object you might have created by hand. That means that it can still be altered after its construction.

The Director class can be modified to allow for more than one creation method. In the case of the Application object, you had only one method, createBand, but having methods that called different configurations using the same builder is possible. For example, you could have methods such as createTrio. By passing different Builder objects, the same method would assemble either a rock trio or a country trio.



Professional PHP5 (Programmer to Programmer Series)
Professional PHP5 (Programmer to Programmer Series)
ISBN: N/A
EAN: N/A
Year: 2003
Pages: 182
BUY ON AMAZON

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net