Строитель (шаблон проектирования)
Материал из 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() );
| порождающие шаблоны проектирования |
| абстрактная фабрика | строитель | фабричный метод | прототип | одиночка | отложенная инициализация |
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:生成器 (设计模式)