빌더 패턴

빌더 패턴()은 객체 지향 프로그래밍에서 복잡한 객체의 생성을 그 객체의 표현과 분리하는 디자인 패턴이다. 1994년 책 《디자인 패턴》이 정의한 23개의 패턴 중 하나로, 생성 패턴(creational pattern)의 일종이다. 빌더 패턴은 복잡한 객체의 생성과 조립을 별도의 빌더 객체로 캡슐화하고, 복잡한 객체를 직접 생성하는 대신 해당 빌더 객체에 원래 객체의 생성을 위임한다.

 구조 
700px

 예 

 자바 
/** "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;
 }
}

/** "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 Cook {
 private PizzaBuilder pizzaBuilder;

 public void setPizzaBuilder(PizzaBuilder pizzaBuilder) {
 this.pizzaBuilder = pizzaBuilder;
 }

 public Pizza getPizza() {
 return pizzaBuilder.getPizza();
 }

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

/** A given type of pizza being constructed. */
public class BuilderExample {
 public static void main(String[] args) {
 Cook cook = new Cook();
 PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
 PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();

 cook.setPizzaBuilder(hawaiianPizzaBuilder);
 cook.constructPizza();

 Pizza pizza = cook.getPizza();
 }
}

 C# 
//Implementation in C#.
class Pizza
{
 string dough;
 string sauce;
 string topping;
 public Pizza() {}
 public void SetDough( string d){ dough = d;}
 public void SetSauce( string s){ sauce = s;}
 public void SetTopping( string t){ topping = t;}
}

//Abstract Builder
abstract class PizzaBuilder
{
 protected Pizza pizza;
 public PizzaBuilder(){}
 public Pizza GetPizza(){ return pizza; }
 public void CreateNewPizza() { pizza = new Pizza(); }

 public abstract void BuildDough();
 public abstract void BuildSauce();
 public abstract void BuildTopping();
}

//Concrete Builder
class HawaiianPizzaBuilder : PizzaBuilder
{
 public override void BuildDough() { pizza.SetDough("cross"); }
 public override void BuildSauce() { pizza.SetSauce("mild"); }
 public override void BuildTopping() { pizza.SetTopping("ham+pineapple"); }
}

//Concrete Builder
class SpicyPizzaBuilder : PizzaBuilder
{
 public override void BuildDough() { pizza.SetDough("pan baked"); }
 public override void BuildSauce() { pizza.SetSauce("hot"); }
 public override void BuildTopping() { pizza.SetTopping("pepparoni+salami"); }
}

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

 public void SetPizzaBuilder (PizzaBuilder pb) { pizzaBuilder = pb; }
 public Pizza GetPizza() { return pizzaBuilder.GetPizza(); }

 public void ConstructPizza() {
 pizzaBuilder.CreateNewPizza();
 pizzaBuilder.BuildDough();
 pizzaBuilder.BuildSauce();
 pizzaBuilder.BuildTopping();
 }
}

/** A customer ordering a pizza. */
class BuilderExample
{
 public static void Main(string[] args) {
 Waiter waiter = new Waiter();
 PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
 PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();

 waiter.SetPizzaBuilder ( hawaiianPizzaBuilder );
 waiter.ConstructPizza();

 Pizza pizza = waiter.GetPizza();
 }
}

 C++ 
// Implementation in C++.

#include 

#include 

#include 

// Product
class Pizza
{
private:
 std::string dough;
 std::string sauce;
 std::string topping;

public:
 Pizza() { }
 ~Pizza() { }

 void SetDough(const std::string& d) { dough = d; };
 void SetSauce(const std::string& s) { sauce = s; };
 void SetTopping(const std::string& t) { topping = t; }

 void ShowPizza()
 {
 std::cout << " Yummy !!!" << std::endl
 << "Pizza with Dough as " << dough
 << ", Sauce as " << sauce
 << " and Topping as " << topping
 << " !!! " << std::endl;
 }
};

// Abstract Builder
class PizzaBuilder
{
protected:
 std::auto_ptr
 pizza;
public:
 PizzaBuilder() {}
 virtual ~PizzaBuilder() {}
 std::auto_ptr
 GetPizza() { return pizza; }

 void createNewPizzaProduct() { pizza.reset (new Pizza); }

 virtual void buildDough()=0;
 virtual void buildSauce()=0;
 virtual void buildTopping()=0;
};

// ConcreteBuilder
class HawaiianPizzaBuilder : public PizzaBuilder
{
public:
 HawaiianPizzaBuilder() : PizzaBuilder() {}
 ~HawaiianPizzaBuilder(){}

 void buildDough() { pizza->SetDough("cross"); }
 void buildSauce() { pizza->SetSauce("mild"); }
 void buildTopping() { pizza->SetTopping("ham and pineapple"); }
};

// ConcreteBuilder
class SpicyPizzaBuilder : public PizzaBuilder
{
public:
 SpicyPizzaBuilder() : PizzaBuilder() {}
 ~SpicyPizzaBuilder() {}

 void buildDough() { pizza->SetDough("pan baked"); }
 void buildSauce() { pizza->SetSauce("hot"); }
 void buildTopping() { pizza->SetTopping("pepperoni and salami"); }
};

// Director
class Waiter
{
private:
 PizzaBuilder* pizzaBuilder;
public:
 Waiter() : pizzaBuilder(NULL) {}
 ~Waiter() { }

 void SetPizzaBuilder(PizzaBuilder* b) { pizzaBuilder = b; }
 std::auto_ptr
 GetPizza() { return pizzaBuilder->GetPizza(); }
 void ConstructPizza()
 {
 pizzaBuilder->createNewPizzaProduct();
 pizzaBuilder->buildDough();
 pizzaBuilder->buildSauce();
 pizzaBuilder->buildTopping();
 }
};

// A customer ordering a pizza.
int main()
{
 Waiter waiter;

 HawaiianPizzaBuilder hawaiianPizzaBuilder;
 waiter.SetPizzaBuilder (&hawaiianPizzaBuilder);
 waiter.ConstructPizza();
 std::auto_ptr
 pizza = waiter.GetPizza();
 pizza->ShowPizza();

 SpicyPizzaBuilder spicyPizzaBuilder;
 waiter.SetPizzaBuilder(&spicyPizzaBuilder);
 waiter.ConstructPizza();
 pizza = waiter.GetPizza();
 pizza->ShowPizza();

 return EXIT_SUCCESS;
}

 비주얼 프롤로그 
Product

 interface pizza
 predicates
 setDough : (string Dough).
 setSauce : (string Sauce).
 setTopping : (string Topping).
 end interface pizza

 class pizza : pizza
 end class pizza

 implement pizza
 facts
 dough : string := "".
 sauce : string := "".
 topping : string := "".
 clauses
 setDough(Dough) :- dough := Dough.
 clauses
 setSauce(Sauce) :- sauce := Sauce.
 clauses
 setTopping(Topping) :- topping := Topping.
 end implement pizza

Abstract Builder

 interface pizzaBuilder
 predicates
 getPizza : () -> pizza Pizza.
 createNewPizzaProduct : ().
 predicates
 buildDough : ().
 buildSauce : ().
 buildTopping : ().
 end interface pizzaBuilder

Visual Prolog does not support abstract classes, but we can create a support class instead:

 interface pizzaBuilderSupport
 predicates from pizzaBuilder
 getPizza, createNewPizzaProduct
 end interface pizzaBuilderSupport

 class pizzaBuilderSupport : pizzaBuilderSupport
 end class pizzaBuilderSupport

 implement pizzaBuilderSupport
 facts
 pizza : pizza := erroneous.
 clauses
 getPizza() = pizza.
 clauses
 createNewPizzaProduct() :- pizza := pizza::new().
 end implement pizzaBuilderSupport

ConcreteBuilder #1

 class hawaiianPizzaBuilder : pizzaBuilder
 end class hawaiianPizzaBuilder

 implement hawaiianPizzaBuilder
 inherits pizzaBuilderSupport

 clauses
 buildDough() :- getPizza():setDough("cross").
 clauses
 buildSauce() :- getPizza():setSauce("mild").
 clauses
 buildTopping() :- getPizza():setTopping("ham+pineapple").
 end implement hawaiianPizzaBuilder

ConcreteBuilder #2

 class spicyPizzaBuilder : pizzaBuilder
 end class spicyPizzaBuilder

 implement spicyPizzaBuilder
 inherits pizzaBuilderSupport

 clauses
 buildDough() :- getPizza():setDough("pan baked").
 clauses
 buildSauce() :- getPizza():setSauce("hot").
 clauses
 buildTopping() :- getPizza():setTopping("pepperoni+salami").
 end implement spicyPizzaBuilder

Director

 interface waiter
 predicates
 setPizzaBuilder : (pizzaBuilder PizzaBuilder).
 getPizza : () -> pizza Pizza.
 predicates
 constructPizza : ().
 end interface waiter

 class waiter : waiter
 end class waiter

 implement waiter
 facts
 pizzaBuilder : pizzaBuilder := erroneous.
 clauses
 setPizzaBuilder(PizzaBuilder) :- pizzaBuilder := PizzaBuilder.
 clauses
 getPizza() = pizzaBuilder:getPizza().
 clauses
 constructPizza() :- 
 pizzaBuilder:createNewPizzaProduct(),
 pizzaBuilder:buildDough(),
 pizzaBuilder:buildSauce(),
 pizzaBuilder:buildTopping().
 end implement waiter

A customer ordering a pizza.

 goal
 Hawaiian_pizzabuilder = hawaiianPizzaBuilder::new(),
 Waiter = waiter::new(),
 Waiter:setPizzaBuilder(Hawaiian_pizzabuilder),
 Waiter:constructPizza(),
 Pizza = Waiter:getPizza().

 펄 
## Product
package pizza;

sub new {
 return bless {
 dough => undef,
 sauce => undef,
 topping => undef
 }, shift;
}

sub set_dough {
 my( $self, $dough ) = @_;
 $self->{dough} = $dough;
}

sub set_sauce {
 my( $self, $sauce ) = @_;
 $self->{sauce} = $sauce;
}

sub set_topping {
 my( $self, $topping ) = @_;
 $self->{topping} = $topping;
}

1;

## Abstract builder
package pizza_builder;

sub new {
 return bless {
 pizza => undef
 }, shift;
}

sub get_pizza {
 my( $self ) = @_;
 return $self->{pizza};
}

sub create_new_pizza_product {
 my( $self ) = @_;
 $self->{pizza} = pizza->new;
}

# This is what an abstract method could look like in perl...

sub build_dough {
 croak("This method must be overridden.");
}

sub build_sauce {
 croak("This method must be overridden.");
}

sub build_topping {
 croak("This method must be overridden.");
}

1;

## Concrete builder
package hawaiian_pizza_builder;

use base qw{ pizza_builder };

sub build_dough {
 my( $self ) = @_;
 $self->{pizza}->set_dough("cross");
}

sub build_sauce {
 my( $self ) = @_;
 $self->{pizza}->set_sauce("mild");
}

sub build_topping {
 my( $self ) = @_;
 $self->{pizza}->set_topping("ham+pineapple");
}

1;

## Concrete builder
package spicy_pizza_builder;

use base qw{ pizza_builder };

sub build_dough {
 my( $self ) = @_;
 $self->{pizza}->set_dough("pan baked");
}

sub build_sauce {
 my( $self ) = @_;
 $self->{pizza}->set_sauce("hot");
}

sub build_topping {
 my( $self ) = @_;
 $self->{pizza}->set_topping("pepperoni+salami");
}

1;

## Director
package waiter;

sub new {
 return bless {
 pizza_builder => undef
 }, shift;
}

sub set_pizza_builder {
 my( $self, $builder ) = @_;
 $self->{pizza_builder} = $builder;
}

sub get_pizza {
 my( $self ) = @_;
 return $self->{pizza_builder}->get_pizza;
}

sub construct_pizza {
 my( $self ) = @_;
 $self->{pizza_builder}->create_new_pizza_product;
 $self->{pizza_builder}->build_dough;
 $self->{pizza_builder}->build_sauce;
 $self->{pizza_builder}->build_topping;
}

1;

## Lets order pizza (client of Director/Builder)
package main

my $waiter = waiter->new;
my $hawaiian_pb = hawaiian_pizza_builder->new;
my $spicy_pb = spicy_pizza_builder->new;

$waiter->set_pizza_builder( $hawaiian_pb );
$waiter->construct_pizza;

my $pizza = $waiter->get_pizza;

print "Serving a nice pizza with:\n";
for (keys %$pizza) {
 print " $pizza->{$_} $_\n";
}

1;

 PHP 
/** Product **/
class Pizza{
 private $dough;
 private $sauce;
 private $topping;
 public function setDough($dough){
 $this->dough = $dough;
 }
 public function setSauce($sauce){
 $this->sauce = $sauce;
 }
 public function setTopping($topping){
 $this->topping = $topping;
 }
}

/** Abstract builder **/
abstract class PizzaBuilder{
 protected $pizza;
 public function __construct(){
 $this->pizza = new Pizza();
 }
 public function getPizza(){
 return $this->pizza;
 }
 abstract function buildDough();
 abstract function buildSauce();
 abstract function buildTopping();
}

/** Concrete builder **/
class SpicyPizza extends PizzaBuilder{
 public function buildDough(){
 $this->pizza->setDough('crispy');
 }
 public function buildSauce(){
 $this->pizza->setSauce('hot');
 }
 public function buildTopping(){
 $this->pizza->setTopping('pepperoni+salami');
 }
}

/** Director **/
class Chef{
 private $pizza_builder;
 public function setPizzaBuilder(PizzaBuilder $pizza_builder){
 $this->pizza_builder = $pizza_builder;
 }
 public function cookPizza(){
 $this->pizza_builder->buildDough();
 $this->pizza_builder->buildSauce();
 $this->pizza_builder->buildTopping();
 }
 public function getPizza(){
 return $this->pizza_builder->getPizza();
 }
}

//Customer orders a Pizza.
$chef = new Chef();

$order = new SpicyPizza();
$chef->setPizzaBuilder($order);
$chef->cookPizza();
$pizza = $chef->getPizza();

print_r($pizza);

 각주 

 같이 보기 
 커링

분류:소프트웨어 디자인 패턴