빌더 패턴

빌더 패턴이란 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴이다. 2 단어 요약 : 생성자 오버로딩 /** "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(); } } //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(); } } // Implementation in C++. #include <iostream> #include <memory> #include <string> // 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> pizza; public: PizzaBuilder() {} virtual ~PizzaBuilder() {} std::auto_ptr<Pizza> 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<Pizza> 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> 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; /** 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); 커링