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

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

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

Цель

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

Плюсы

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

Применение

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

Примеры

Пример на 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:生成器 (设计模式)

Если вам нравится SbUP.com Сайт, вы можете поддержать его - BTC: bc1qppjcl3c2cyjazy6lepmrv3fh6ke9mxs7zpfky0 , TRC20 и ещё....