Строитель (шаблон проектирования)

Материал из Seo Wiki - Поисковая Оптимизация и Программирование

Перейти к: навигация, поиск

Строитель, (англ. Builder)порождающий шаблон проектирования.

Содержание

Цель

Отделяет конструирование сложного объекта от его представления, так что в результате одного и того же процесса конструирования могут получаться разные представления.

Плюсы

  • позволяет изменять внутреннее представление продукта;
  • изолирует код, реализующий конструирование и представление;
  • дает более тонкий контроль над процессом конструирования.

Применение

  • алгоритм создания сложного объекта не должен зависеть от того, из каких частей состоит объект и как они стыкуются между собой;
  • процесс конструирования должен обеспечивать различные представления конструируемого объекта.

Примеры

Пример на Java

 /** "Product" Maksatzadr*/
 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 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. */
 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();
    }
 }

Пример на С#

 using System;
 using System.Collections.Generic;
 
 namespace Builder
 {
 
  public class MainApp
  {
    public static void Main()
    {
      // Create director and builders
      Director director = new Director();
 
      Builder b1 = new ConcreteBuilder1();
      Builder b2 = new ConcreteBuilder2();
 
      // Construct two products
      director.Construct(b1);
      Product p1 = b1.GetResult();
      p1.Show();
 
      director.Construct(b2);
      Product p2 = b2.GetResult();
      p2.Show();
 
      // Wait for user
      Console.Read();
    }
  }
 
  // "Director"
 
  class Director
  {
    // Builder uses a complex series of steps
    public void Construct(Builder builder)
    {
      builder.BuildPartA();
      builder.BuildPartB();
    }
  }
 
  // "Builder"
 
  abstract class Builder
  {
    public abstract void BuildPartA();
    public abstract void BuildPartB();
    public abstract Product GetResult();
  }
 
  // "ConcreteBuilder1"
 
  class ConcreteBuilder1 : Builder
  {
    private readonly Product product = new Product();
 
    public override void BuildPartA()
    {
      product.Add("PartA");
    }
 
    public override void BuildPartB()
    {
      product.Add("PartB");
    }
 
    public override Product GetResult()
    {
      return product;
    }
  }
 
  // "ConcreteBuilder2"
 
  class ConcreteBuilder2 : Builder
  {
    private readonly Product product = new Product();
 
    public override void BuildPartA()
    {
      product.Add("PartX");
    }
 
    public override void BuildPartB()
    {
      product.Add("PartY");
    }
 
    public override Product GetResult()
    {
      return product;
    }
  }
 
  // "Product"
 
  class Product
  {
    private readonly List<string> parts = new List<string>();
 
    public void Add(string part)
    {
      parts.Add(part);
    }
 
    public void Show()
    {
      Console.WriteLine("\nProduct Parts -------");
      foreach (string part in parts)
        Console.WriteLine(part);
    }
  }
 }

Пример на C++

// Реализация на 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();
    }
};
 
// Клиент заказывает две пиццы.
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;
}

Пример на JavaScript

// Product
function Pizza() {
	var dublicate = this; // постоянная ссылка на инстанцируемый объект для вызова при любом this
	var dough;
	var sauce;
	var topping;
 
	this.setDough = function(val) {
		dough = val;
	};
	this.setSauce = function(val) {
		sauce = val;
	};
	this.setTopping = function(val) {
		topping = val;
	};
 
	// из-за особенностей языка, геттеры (пусть они нам и не понадобятся) 
	// должны быть определены в той же функции, что и локальные переменные
	this.getDough = function() {
		return dough;
	};
	this.getSauce = function() {
		return sauce;
	};
	this.getTopping = function() {
		return topping;
	};
 
	// мы должны создать метод, изменяющий св-ва уже созданного объекта
	// (см. createNewPizzaProduct)
	this.clear = function() {
		dublicate.setDough(undefined);
		dublicate.setSauce(undefined);
		dublicate.setTopping(undefined);
	};
}
 
// Abstract Builder
function PizzaBuilder() {
	var pizza = new Pizza();
 
	this.getPizza = function() {
		return pizza;
	};
	this.createNewPizzaProduct = function() {
		// если мы просто поменяем зн-е переменной pizza, то изменение никак
		// не отразится на дочерних классах, т.к. внутри них переменная pizza
		// ссылается на «старую» область памяти
		pizza.clear();
		// если внутри реализаций (HawaiianPizzaBuilder, SpicyPizzaBuilder)
		// мы, вместо переменной pizza, будем использовать метод getPizza,
		// то можно использовать
		// pizza = new Pizza();
		// и метод clear у Pizza не понадобится
	};
 
	this.buildDough = function(val) { };
	this.buildSauce = function(val) { };
	this.buildTopping = function(val) { };
}
 
// ConcreteBuilder
function HawaiianPizzaBuilder() {
	PizzaBuilder.call(this);
	var pizza = this.getPizza(); // имитация protected
 
	this.buildDough = function() { pizza.setDough("cross"); };
	this.buildSauce = function() { pizza.setSauce("mild"); };
	this.buildTopping = function() { pizza.setTopping("ham+pineapple"); };
}
 
function SpicyPizzaBuilder() {
	PizzaBuilder.call(this);
	var pizza = this.getPizza();
 
	this.buildDough = function() { pizza.setDough("pan baked"); };
	this.buildSauce = function() { pizza.setSauce("hot"); };
	this.buildTopping = function() { pizza.setTopping("pepperoni+salami"); };
}
 
// Director
function Waiter() {
	var pizzaBuilder;
 
	this.setPizzaBuilder = function(builder) {
		pizzaBuilder = builder;
	};
	this.getPizza = function() {
		return pizzaBuilder.getPizza();
	};
 
	this.constructPizza = function() {
		pizzaBuilder.createNewPizzaProduct();
		pizzaBuilder.buildDough();
		pizzaBuilder.buildSauce();
		pizzaBuilder.buildTopping();
	};
}
 
// Клиент заказывает две пиццы
var pizza;
var waiter = new Waiter();
 
var hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
waiter.setPizzaBuilder( hawaiianPizzaBuilder );
waiter.constructPizza();
pizza = waiter.getPizza();
alert( pizza.getDough() +", "+ pizza.getSauce() +", "+ pizza.getTopping() );
 
var spicyPizzaBuilder = new SpicyPizzaBuilder();
waiter.setPizzaBuilder( spicyPizzaBuilder );
waiter.constructPizza();
pizza = waiter.getPizza();
alert( pizza.getDough() +", "+ pizza.getSauce() +", "+ pizza.getTopping() );

Вариант (урезанный) без использования локальной переменной dublicate и метода clear у Pizza

// Product
function Pizza() {
	var dough;
	var sauce;
	var topping;
 
	// методы setDough, setSauce, setTopping, getDough, getSauce, getTopping без изменений
	// метод clear не нужен
}
 
// Abstract Builder
function PizzaBuilder() {
	var pizza = new Pizza();
 
	this.getPizza = function() {
		return pizza;
	};
	this.createNewPizzaProduct = function() {
		// внутри реализаций (HawaiianPizzaBuilder, SpicyPizzaBuilder)
		// будем использовать метод getPizza
		pizza = new Pizza();
	};
 
	this.buildDough = function(val) { };
	this.buildSauce = function(val) { };
	this.buildTopping = function(val) { };
}
 
// ConcreteBuilder
function HawaiianPizzaBuilder() {
	PizzaBuilder.call(this);
	// вместо имитации protected будем использовать ссылку на геттер
	var pizza = this.getPizza;
 
	this.buildDough = function() { pizza().setDough("cross"); };
	this.buildSauce = function() { pizza().setSauce("mild"); };
	this.buildTopping = function() { pizza().setTopping("ham+pineapple"); };
}
 
function SpicyPizzaBuilder() {
	PizzaBuilder.call(this);
	var pizza = this.getPizza;
 
	this.buildDough = function() { pizza().setDough("pan baked"); };
	this.buildSauce = function() { pizza().setSauce("hot"); };
	this.buildTopping = function() { pizza().setTopping("pepperoni+salami"); };
}
 
// Director
function Waiter() {
	// без изменений
}
 
// Клиент заказывает две пиццы
var pizza;
var waiter = new Waiter();
 
var hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
waiter.setPizzaBuilder( hawaiianPizzaBuilder );
waiter.constructPizza();
pizza = waiter.getPizza(); // возвращенный объект теперь не изменится при constructPizza
waiter.constructPizza(); 
pizza2 = waiter.getPizza();
alert( pizza.getDough() +", "+ pizza.getSauce() +", "+ pizza.getTopping() );
alert( pizza2.getDough() +", "+ pizza2.getSauce() +", "+ pizza2.getTopping() );
 
var spicyPizzaBuilder = new SpicyPizzaBuilder();
waiter.setPizzaBuilder( spicyPizzaBuilder );
waiter.constructPizza();
pizza = waiter.getPizza();
alert( pizza.getDough() +", "+ pizza.getSauce() +", "+ pizza.getTopping() );



порождающие шаблоны проектирования
абстрактная фабрика | строитель | фабричный метод | прототип | одиночка | отложенная инициализация
bg:Строител (шаблон)

ca:Builder de:Erbauer (Entwurfsmuster) en:Builder pattern es:Builder (patrón de diseño) fr:Monteur (patron de conception) it:Builder ja:Builder パターン ko:빌더 패턴 pl:Budowniczy (wzorzec projektowy) pt:Builder uk:Будівник (шаблон проектування) zh:生成器 (设计模式)

Личные инструменты

Served in 0.248 secs.