Hack70.Abstract Construction Code with a Builder


Hack 70. Abstract Construction Code with a Builder

Use the Builder pattern to abstract code that performs a routine construction task, such as composing HTML or text for an email.

I've always found that code that constructs something is some of the most elegant code in a system. I suppose that's just because I spent a year writing a book on code generation, which is all about constructing code.

By the way, the book is Code Generation in Action (Manning). It_s still available and makes an excellent holiday gift for friends and family.


An example of construction code is the code that reads an XML document off the disk and constructs an in-memory representation of that structure. Another is a module of code that constructs an email message to tell a customer she is behind on her payments.

It's the late-payment mail that I want to focus on in this hack; but I'm going to do it with a twist. I'm going to use the Builder pattern so that the same code that creates a message in HTML can also create a message in XHTML or text format.

I'm going to have the code that writes the past-due notice use a builder instead of just creating the string directly. This builder object will have a set of methods, as shown in Figure 7-4. The startBody( ) and endBody() methods wrap the creation of the message. The addText() method adds some text, and the addBreak( ) method adds a line break.

Figure 7-4. The output builder hierarchy


The OutputBuilder abstract class has several concrete instantiations. One is HTMLBuilder, which builds HTML. Deriving from that is XHTMLBuilder, which alters the behavior of its parent just enough to make the output XHTML compliant. And finally there's TextBuilder, which builds a plaintext representation of the message.

7.5.1. The Code

Save the code in Example 7-4 as builder.php.

Example 7-4. A set of example builder classes and some test code
 <?php abstract class OutputBuilder {   abstract function getOutput();   abstract function startBody();   abstract function endBody();   abstract function addText( $text );   abstract function addBreak(); } class HTMLBuilder extends OutputBuilder {   private $buffer = "";   public function getOutput()   {     return "<html>\n".$this->buffer."\n</html>\n";   }   public function startBody() { $this->add( "<body>" ); }   public function endBody() { $this->add( "</body>" ); }   public function addText( $text ) { $this->add( $text ); }   public function addBreak() { $this->add( "<br>\n" ); }   protected function add( $text ) { $this->buffer .= $text; } } class XHTMLBuilder extends HTMLBuilder {   public function addBreak() { $this->add( "<br />\n" ); } } class TextBuilder extends OutputBuilder {   private $buffer = "";   public function getOutput()   {     return $this->buffer."\n";   }   public function startBody() { }   public function endBody() { }   public function addText( $text ) { $this->add( $text ); }   public function addBreak() { $this->add( "\n" ); }   protected function add( $text ) { $this->buffer .= $text; } } function buildDocument( $builder ) {   $builder->startBody();   $builder->addText( 'Jack,' );   $builder->addBreak();   $builder->addText( 'You owe us $10,000. Have a NICE day.' );   $builder->endBody(); } print "HTML:\n\n"; $html = new HTMLBuilder(); buildDocument( $html ); echo( $html->getOutput() ); print "\nXHTML:\n\n"; $xhtml = new XHTMLBuilder(); buildDocument( $xhtml ); echo( $xhtml->getOutput() ); print "\nText:\n\n"; $text = new TextBuilder(); buildDocument( $text ); echo( $text->getOutput() ); ?> 

7.5.2. Running the Hack

You run this hack on the command line using the PHP command-line interpreter:

 % php builder.php HTML: <html> <body>Jack,<br> You owe us $10,000. Have a NICE day.</body> </html> XHTML: <html> <body>Jack,<br /> You owe us $10,000. Have a NICE day.</body> </html> Text: Jack, You owe us $10,000. Have a NICE day. 

This shows the output of the three different builders. The first is the HTML version with the correct HTML tags and the <br> tag. The XHTML tag changes the behavior slightly so that the <br> tag has become <br />. The text version is just plain text, with the break turned into a simple carriage return.

Looking at the code, you see the definition of the abstract OutputBuilder class at the start of the file, followed by the concrete instantiations for the different flavors of output. The buildDocument( ) function uses the builder to build the message. The code at the bottom of the file tests the buildDocument( ) function with each of the different flavors of builders.

You can use a Builder pattern in several places in a PHP web application:


File reading

Any time you are parsing a file, you should use a Builder pattern to abstract the parsing of the file from the creation of the in-memory data structures that hold the data in the file.


File writing

As I showed in this hack, you can use a Builder pattern to create multiple output formats from a single document-building system.


Generating code

You can use builders to generate code for any number of languages from a single generation system.

The .NET Framework uses the Builder pattern when creating HTML for the output page to allow the same control to generate multiple flavors of HTML based on the type of web browser requesting the page.



PHP Hacks
PHP Hacks: Tips & Tools For Creating Dynamic Websites
ISBN: 0596101392
EAN: 2147483647
Year: 2006
Pages: 163

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