-
Notifications
You must be signed in to change notification settings - Fork 124
Expand file tree
/
Copy pathmain.cc
More file actions
271 lines (243 loc) · 11 KB
/
main.cc
File metadata and controls
271 lines (243 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#include <iostream>
#include <string>
#include <vector>
/**
* EN: Builder Design Pattern
*
* Intent: Lets you construct complex objects step by step. The pattern allows
* you to produce different types and representations of an object using the
* same construction code.
*
* RU: Паттерн Строитель
*
* Назначение: Позволяет создавать сложные объекты пошагово. Строитель даёт
* возможность использовать один и тот же код строительства для получения разных
* представлений объектов.
*/
/**
* EN: It makes sense to use the Builder pattern only when your products are
* quite complex and require extensive configuration.
*
* Unlike in other creational patterns, different concrete builders can produce
* unrelated products. In other words, results of various builders may not
* always follow the same interface.
*
* RU: Имеет смысл использовать паттерн Строитель только тогда, когда ваши
* продукты достаточно сложны и требуют обширной конфигурации.
*
* В отличие от других порождающих паттернов, различные конкретные строители
* могут производить несвязанные продукты. Другими словами, результаты различных
* строителей могут не всегда следовать одному и тому же интерфейсу.
*/
class Product1{
public:
std::vector<std::string> parts_;
void ListParts()const{
std::cout << "Product parts: ";
for (size_t i=0;i<parts_.size();i++){
if(parts_[i]== parts_.back()){
std::cout << parts_[i];
}else{
std::cout << parts_[i] << ", ";
}
}
std::cout << "\n\n";
}
};
/**
* EN: The Builder interface specifies methods for creating the different parts
* of the Product objects.
*
* RU: Интерфейс Строителя объявляет создающие методы для различных частей
* объектов Продуктов.
*/
class Builder{
public:
virtual ~Builder(){}
virtual void ProducePartA() const =0;
virtual void ProducePartB() const =0;
virtual void ProducePartC() const =0;
};
/**
* EN: The Concrete Builder classes follow the Builder interface and provide
* specific implementations of the building steps. Your program may have several
* variations of Builders, implemented differently.
*
* RU: Классы Конкретного Строителя следуют интерфейсу Строителя и предоставляют
* конкретные реализации шагов построения. Ваша программа может иметь несколько
* вариантов Строителей, реализованных по-разному.
*/
class ConcreteBuilder1 : public Builder{
private:
Product1* product;
/**
* EN: A fresh builder instance should contain a blank product object, which
* is used in further assembly.
*
* RU: Новый экземпляр строителя должен содержать пустой объект продукта,
* который используется в дальнейшей сборке.
*/
public:
ConcreteBuilder1(){
this->Reset();
}
~ConcreteBuilder1(){
delete product;
}
void Reset(){
this->product= new Product1();
}
/**
* EN: All production steps work with the same product instance.
*
* RU: Все этапы производства работают с одним и тем же экземпляром
* продукта.
*/
void ProducePartA()const override{
this->product->parts_.push_back("PartA1");
}
void ProducePartB()const override{
this->product->parts_.push_back("PartB1");
}
void ProducePartC()const override{
this->product->parts_.push_back("PartC1");
}
/**
* EN: Concrete Builders are supposed to provide their own methods for
* retrieving results. That's because various types of builders may create
* entirely different products that don't follow the same interface.
* Therefore, such methods cannot be declared in the base Builder interface
* (at least in a statically typed programming language). Note that PHP is a
* dynamically typed language and this method CAN be in the base interface.
* However, we won't declare it there for the sake of clarity.
*
* Usually, after returning the end result to the client, a builder instance
* is expected to be ready to start producing another product. That's why
* it's a usual practice to call the reset method at the end of the
* `getProduct` method body. However, this behavior is not mandatory, and
* you can make your builders wait for an explicit reset call from the
* client code before disposing of the previous result.
*
* RU: Конкретные Строители должны предоставить свои собственные методы
* получения результатов. Это связано с тем, что различные типы строителей
* могут создавать совершенно разные продукты с разными интерфейсами.
* Поэтому такие методы не могут быть объявлены в базовом интерфейсе
* Строителя (по крайней мере, в статически типизированном языке
* программирования). Обратите внимание, что PHP является динамически
* типизированным языком, и этот метод может быть в базовом интерфейсе.
* Однако мы не будем объявлять его здесь для ясности.
*
* Как правило, после возвращения конечного результата клиенту, экземпляр
* строителя должен быть готов к началу производства следующего продукта.
* Поэтому обычной практикой является вызов метода сброса в конце тела
* метода getProduct. Однако такое поведение не является обязательным, вы
* можете заставить своих строителей ждать явного запроса на сброс из кода
* клиента, прежде чем избавиться от предыдущего результата.
*/
/**
* EN: Please be careful here with the memory ownership. Once you call GetProduct
* the user of this function is responsable to release this memory. Here could be
* a better option to use smart pointers to avoid memory leaks
*
* RU:
*
*/
Product1* GetProduct() {
Product1* result= this->product;
this->Reset();
return result;
}
};
/**
* EN: The Director is only responsible for executing the building steps in a
* particular sequence. It is helpful when producing products according to a
* specific order or configuration. Strictly speaking, the Director class is
* optional, since the client can control builders directly.
*
* RU: Директор отвечает только за выполнение шагов построения в определённой
* последовательности. Это полезно при производстве продуктов в определённом
* порядке или особой конфигурации. Строго говоря, класс Директор необязателен,
* так как клиент может напрямую управлять строителями.
*/
class Director{
/**
* @var Builder
*/
private:
Builder* builder_;
/**
* EN: The Director works with any builder instance that the client code
* passes to it. This way, the client code may alter the final type of the
* newly assembled product.
*
* RU: Директор работает с любым экземпляром строителя, который передаётся
* ему клиентским кодом. Таким образом, клиентский код может изменить
* конечный тип вновь собираемого продукта.
*/
public:
void set_builder(Builder* builder){
this->builder_=builder;
}
/**
* EN: The Director can construct several product variations using the same
* building steps.
*
* RU: Директор может строить несколько вариаций продукта, используя
* одинаковые шаги построения.
*/
void BuildMinimalViableProduct(){
this->builder_->ProducePartA();
}
void BuildFullFeaturedProduct(){
this->builder_->ProducePartA();
this->builder_->ProducePartB();
this->builder_->ProducePartC();
}
};
/**
* EN: The client code creates a builder object, passes it to the director and
* then initiates the construction process. The end result is retrieved from the
* builder object.
*
* RU: Клиентский код создаёт объект-строитель, передаёт его директору, а затем
* инициирует процесс построения. Конечный результат извлекается из
* объекта-строителя.
*/
/**
* EN: I used raw pointers for simplicity however you may prefer to use smart pointers here
*
* RU:
*
*/
void ClientCode(Director& director)
{
ConcreteBuilder1* builder = new ConcreteBuilder1();
director.set_builder(builder);
std::cout << "Standard basic product:\n";
director.BuildMinimalViableProduct();
Product1* p= builder->GetProduct();
p->ListParts();
delete p;
std::cout << "Standard full featured product:\n";
director.BuildFullFeaturedProduct();
p= builder->GetProduct();
p->ListParts();
delete p;
// EN: Remember, the Builder pattern can be used without a Director class.
//
// RU: Помните, что паттерн Строитель можно использовать без класса
// Директор.
std::cout << "Custom product:\n";
builder->ProducePartA();
builder->ProducePartC();
p=builder->GetProduct();
p->ListParts();
delete p;
delete builder;
}
int main(){
Director* director= new Director();
ClientCode(*director);
delete director;
return 0;
}