Строитель (шаблон проектирования)
Строитель, (англ. Builder) — порождающий шаблон проектирования.
Цель
Отделяет конструирование сложного объекта от его представления, так что в результате одного и того же процесса конструирования могут получаться разные представления.
Плюсы
- позволяет изменять внутреннее представление продукта;
- изолирует код, реализующий конструирование и представление;
- дает более тонкий контроль над процессом конструирования.
Применение
- алгоритм создания сложного объекта не должен зависеть от того, из каких частей состоит объект и как они стыкуются между собой;
- процесс конструирования должен обеспечивать различные представления конструируемого объекта.
Примеры
Пример на Java
<source lang="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(); } }
</source>
Пример на С#
<source lang="csharp">
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);
}
}
}
</source>
Пример на C++
<source lang="cpp"> // Реализация на 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;
} </source>
Пример на JavaScript
<source lang="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() ); </source>
Вариант (урезанный) без использования локальной переменной dublicate и метода clear у Pizza
<source lang="javascript"> // 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() ); </source>
| порождающие шаблоны проектирования |
| абстрактная фабрика | строитель | фабричный метод | прототип | одиночка | отложенная инициализация |
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 и ещё....