Будівельник (шаблон проєктування)
Будівельник (англ. Builder) — шаблон проєктування, належить до класу твірних шаблонів. На відміну від шаблону абстрактної фабрики і фабричного методу, ціль яких є застосування поліморфізму, задачею шаблону будівельника є забезпечення реалізації антишаблону телескопічного (багатоступеневого) конструювання. Антишаблон «телескопічний конструктор» коли різна комбінація параметрів конструктора призводить до появи експоненційної множини конструкторів. Замість того, щоб використовувати набір конструкторів, використовують шаблон будівельник, згідно з яким використовують інший об'єкт (будівельник), що отримує на вхід вхідні параметри по одному, крок за кроком, і повертає за один прохід результуючий створений об'єкт.
Відокремлює конструювання складного об'єкта від його подання, таким чином у результаті одного й того ж процесу конструювання можуть бути отримані різні подання.
Вам запропоновано створити систему планування екскурсій по Паттернленду — новому парку розваг. Гості парку можуть вибрати готель, замовити квитки на атракціони, зарезервувати місця в ресторані і навіть замовити спеціальні заходи. Поїздки можуть відрізнятися за кількістю днів і складу розважальної програми. Наприклад, місцевий житель не бажає зупинятися у готелі, але хоче замовити обід та спеціальні заходи. Другий гість прилітає літаком і йому необхідно забронювати номер в готелі, столик в ресторані і квитки на заходи. Таким чином, нам потрібна гнучка структура даних, яка може представляти програму поселення з усіма можливими варіаціями; крім того, побудова програми може складатися з декількох кроків.
Слід використовувати шаблон Будівельник коли:
- алгоритм створення складного об'єкта не повинен залежати від того, з яких частин складається об'єкт та як вони стикуються поміж собою;
- процес конструювання повинен забезпечити різні подання об'єкта, що конструюється.
- Builder — будівельник:
- визначає абстрактний інтерфейс для створення частин об'єкта Product;
- ConcreteBuilder — конкретний будівельник:
- конструює та збирає докупи частини продукту шляхом реалізації інтерфейсу Builder;
- визначає подання, що створюється, та слідкує на ним;
- надає інтерфейс для доступу до продукту;
- Director — керівник:
- конструює об'єкт, користуючись інтерфейсом Builder;
- Product — продукт:
- подає складний конструйований об'єкт. ConcreteBuilder будує внутрішнє подання продукту та визначає процес його складання;
- вносить класи, що визначають складені частини, у тому числі інтерфейси для складання кінцевого результату з частин.
- дозволяє змінювати внутрішнє представлення продукту;
- ізолює код, який реалізує конструювання та подання;
- дає тонший контроль над процесом конструювання.
- Потрібно створити окремий ConcreteBuilder для кожного окремого продукту.
- клієнт створює об'єкт-управитель Director та конфігурує його потрібним об'єктом-будівником Builder;
- управитель повідомляє будівельника про те, що потрібно побудувати наступну частину продукту;
- будівельник оброблює запити управителя та додає нові частини до продукту;
- клієнт забирає продукт у будівельника.
#include <iostream>
#include <string>
using namespace std;
// Builder
class CReportBuilder
{
public:
virtual ~CReportBuilder() {};
virtual void CreateHeader() = 0;
virtual void CreateBody() = 0;
virtual void CreateFooter() = 0;
virtual void Print()
{
cout << m_strReport << endl;
};
protected:
string m_strReport;
};
// Конкретний будівельник 1
struct CTextReportBuilder : public CReportBuilder
{
virtual ~CTextReportBuilder() {};
virtual void CreateHeader()
{
m_strReport.append("SIMPLE REPORT'S HEADER \n");
};
virtual void CreateBody()
{
m_strReport.append("\n\"Simple Report's Main Text\"\n \n");
};
virtual void CreateFooter()
{
m_strReport.append("Simple Report's Footer \n");
};
};
// Конкретний будівельник 2
struct CHTMLReportBuilder : public CReportBuilder
{
virtual ~CHTMLReportBuilder() {};
virtual void CreateHeader()
{
m_strReport.append("<HTML><BODY> \n");
m_strReport.append("<H1>HTML REPORT'S HEADER</H1> \n");
};
virtual void CreateBody()
{
m_strReport.append("<p>\"HTML Report's Main Text\"</p> \n");
};
virtual void CreateFooter()
{
m_strReport.append("<p><i>HTML Report's Footer</i></p> \n");
m_strReport.append("</BODY></HTML>");
};
};
// Director. Створює продукт використовуючи інтерфейс Будівельника
void CreateReport(CReportBuilder& report)
{
report.CreateHeader();
report.CreateBody();
report.CreateFooter();
};
void main()
{
CHTMLReportBuilder Report; // Product
CreateReport(Report);
Report.Print();
}
class DeathStarBuilder {
var x: Double?
var y: Double?
var z: Double?
typealias BuilderClosure = (DeathStarBuilder) -> ()
init(buildClosure: BuilderClosure) {
buildClosure(self)
}
}
struct DeathStar : CustomStringConvertible {
let x: Double
let y: Double
let z: Double
init?(builder: DeathStarBuilder) {
if let x = builder.x, y = builder.y, z = builder.z {
self.x = x
self.y = y
self.z = z
} else {
return nil
}
}
var description:String {
return "Death Star at (x:\(x) y:\(y) z:\(z))"
}
}
let empire = DeathStarBuilder { builder in
builder.x = 0.1
builder.y = 0.2
builder.z = 0.3
}
let deathStar = DeathStar(builder:empire)
- Design Patterns: Elements of Reusable Object-Oriented Software [Архівовано 9 листопада 2012 у Wayback Machine.]
- Design Patterns implemented in Swift 2 [Архівовано 30 січня 2016 у Wayback Machine.]
Алан Шаллоуей, Джеймс Р. Тротт. Шаблоны проектирования. Новый подход к объектно-ориентированному анализу и проектированию = Design Patterns Explained: A New Perspective on Object-Oriented Design. — М. : «Вильямс», 2002. — 288 с. — ISBN 0-201-71594-5.