Friday, February 05, 2010

Design patterns : Builder

The purpose of a builder is to separate the construction process of a complex object from its representation so that the same construction process can be used to create different representations.

The participating actors are a "director" which interprets the information and invokes the "builder" to get the object built. The builder creates parts of a complex object each time it is called and maintains the state of the object. Eventually when the product is complete, the client can retrieve the product from the "builder".

Lets check out some code:

In PHP

abstract class AbstractPageBuilder //abstract builder
{
  abstract function getPage();
}

abstract class AbstractPageDirector //abstract director
{
  abstract function __construct(AbstractPageBuilder $builder_in);
  abstract function buildPage();
  abstract function getPage();
}

class HTMLPage //product 
{
  private $page = NULL;
  private $page_title = NULL;
  private $page_heading = NULL;
  private $page_text = NULL;
  function __construct() 
  {  }
  function showPage() 
  {
    return $this->page;
  }
  function setTitle($title_in) 
  {
    $this->page_title = $title_in;
  }
  function setHeading($heading_in) 
  {
    $this->page_heading = $heading_in;
  }
  function setText($text_in) 
  {
    $this->page_text .= $text_in;
  }
  function formatPage() 
  {
    $this->page  = "<html>\n";
    $this->page .= "<head><title>".$this->page_title."</title></head>\n";
    $this->page .= "<body>\n";
    $this->page .= "<h1>".$this->page_heading."</h1>\n";
    $this->page .= $this->page_text;
    $this->page .= "\n</body>\n";
    $this->page .= "</html>";
  }
}

class HTMLPageBuilder extends AbstractPageBuilder //concrete builder
{
  private $page = NULL;
  function __construct() 
  {
    $this->page = new HTMLPage();
  }
  function setTitle($title_in) 
  {
    $this->page->setTitle($title_in);
  }
  function setHeading($heading_in) 
  {
    $this->page->setHeading($heading_in);
  }
  function setText($text_in) 
  {
    $this->page->setText($text_in);
  }
  function formatPage() 
  {
    $this->page->formatPage();
  }
  function getPage() 
  {
    return $this->page;
  }
}

class HTMLPageDirector extends AbstractPageDirector //concrete director
{
  private $builder = NULL;
  public function __construct(AbstractPageBuilder $builder_in) 
  {
    $this->builder = $builder_in;
  }
  public function buildPage() 
  {
    $this->builder->setTitle('Testing HTMLPage Title');
    $this->builder->setHeading('Testing HTMLPage Heading');
    $this->builder->setText('Body1 Testing, testing, testing!');
    $this->builder->setText('Body2 Testing, testing, testing, or!');
    $this->builder->setText('Body3 Testing, testing, testing, more!');
    $this->builder->formatPage();
  }
  public function getPage() 
  {
    return $this->builder->getPage();
  }
}

echo("BEGIN\n");

$pageBuilder = new HTMLPageBuilder();
$pageDirector = new HTMLPageDirector($pageBuilder);
$pageDirector->buildPage();
$page = $pageDirector->GetPage();
echo $page->showPage();
echo "\nEND\n";

Output:

BEGIN
<html>
<head><title>Testing HTMLPage Title</title></head>
<body>
<h1>Testing HTMLPage Heading</h1>
Body1 Testing, testing, testing!Body2 Testing, testing, testing, or!Body3 Testing, testing, testing, more!
</body>
</html>
END


The classic pizza example in java

/* "Product" */
class Pizza 
{
  private String dough = "";
  private String sauce = "";
  private String topping = "";

  public void setDough(String dough)     { this.dough = dough; }
  public void setSauce(String sauce)     { this.sauce = sauce; }
  public void setTopping(String topping) { this.topping = topping; }

  public void showPizza()
  {
    System.out.println("PIZZA........");
    System.out.println("Dough : "+this.dough);
    System.out.println("Sauce : "+this.sauce);
    System.out.println("Topping : "+this.topping);
    System.out.println("----------");
  }
}

/* "Abstract Builder" */
abstract class PizzaBuilder 
{
  protected Pizza pizza;

  public Pizza getPizza() { return pizza; }
  public void createNewPizzaProduct() 
  { 
    pizza = new Pizza(); 
  }

  public abstract void buildDough();
  public abstract void buildSauce();
  public abstract void buildTopping();

}

/* "ConcreteBuilder" */
class HawaiianPizzaBuilder extends PizzaBuilder 
{
  public void buildDough()   { pizza.setDough("cross"); }
  public void buildSauce()   { pizza.setSauce("mild"); }
  public void buildTopping() { pizza.setTopping("ham+pineapple"); }
}

/* "ConcreteBuilder" */
class SpicyPizzaBuilder extends PizzaBuilder 
{
  public void buildDough()   { pizza.setDough("pan baked"); }
  public void buildSauce()   { pizza.setSauce("hot"); }
  public void buildTopping() { pizza.setTopping("pepperoni+salami"); }
}

/* "Director" */
class Waiter 
{
  private PizzaBuilder pizzaBuilder;

  public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; }
  public Pizza getPizza() { return pizzaBuilder.getPizza(); }

  public void constructPizza() 
  {
    pizzaBuilder.createNewPizzaProduct();
    pizzaBuilder.buildDough();
    pizzaBuilder.buildSauce();
    pizzaBuilder.buildTopping();
  }
}

/* A customer ordering a pizza. */
public class BuilderExample 
{
  public static void main(String[] args) 
  {
    Waiter waiter = new Waiter();
    PizzaBuilder hawaiian_pizzabuilder = new HawaiianPizzaBuilder();
    PizzaBuilder spicy_pizzabuilder = new SpicyPizzaBuilder();

    waiter.setPizzaBuilder( hawaiian_pizzabuilder );
    waiter.constructPizza();

    Pizza pizza = waiter.getPizza();
    pizza.showPizza();
  }
}

Output:

PIZZA........
Dough : cross
Sauce : mild
Topping : ham+pineapple
----------

No comments: