Skip to content

Commit 67264df

Browse files
committed
Builder: improve conceptual example
1 parent fe327df commit 67264df

File tree

2 files changed

+180
-75
lines changed

2 files changed

+180
-75
lines changed

Builder.Conceptual/Output.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
Standart basic product:
1+
Standard basic product:
22
Product parts: PartA1
33

4-
Standart full featured product:
4+
Standard full featured product:
55
Product parts: PartA1, PartB1, PartC1
66

77
Custom product:

Builder.Conceptual/Program.cs

Lines changed: 178 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,232 @@
1-
using System;
1+
// EN: Builder Design Pattern
2+
//
3+
// Intent: Separate the construction of a complex object from its representation
4+
// so that the same construction process can create different representations.
5+
//
6+
// RU: Паттерн Строитель
7+
//
8+
// Назначение: Отделяет построение сложного объекта от его
9+
// представления так, что один и тот же процесс построения может создавать
10+
// разные представления объекта.
11+
12+
using System;
213
using System.Collections.Generic;
314

415
namespace RefactoringGuru.DesignPatterns.Builder.Conceptual
516
{
6-
class Program
17+
// EN: The Builder interface specifies methods for creating the different
18+
// parts of the Product objects.
19+
//
20+
// RU: Интерфейс Строителя объявляет создающие методы для различных частей
21+
// объектов Продуктов.
22+
public interface Builder
723
{
8-
static void Main(string[] args)
9-
{
10-
Builder builder = new ConcreteBuilder();
11-
Director director = new Director(builder);
12-
13-
Client client = new Client();
14-
client.ClientCode(director, builder);
15-
}
24+
void BuildPartA();
25+
26+
void BuildPartB();
27+
28+
void BuildPartC();
1629
}
17-
18-
public class Client
30+
31+
// EN: The Concrete Builder classes follow the Builder interface and provide
32+
// specific implementations of the building steps. Your program may have
33+
// several variations of Builders, implemented differently.
34+
//
35+
// RU: Классы Конкретного Строителя следуют интерфейсу Строителя и
36+
// предоставляют конкретные реализации шагов построения. Ваша программа
37+
// может иметь несколько вариантов Строителей, реализованных по-разному.
38+
public class ConcreteBuilder : Builder
1939
{
20-
public void ClientCode(Director director, Builder builder)
40+
private Product _product = new Product();
41+
42+
// EN: A fresh builder instance should contain a blank product object,
43+
// which is used in further assembly.
44+
//
45+
// RU: Новый экземпляр строителя должен содержать пустой объект
46+
// продукта, который используется в дальнейшей сборке.
47+
public ConcreteBuilder()
2148
{
22-
Console.WriteLine("Standart basic product:");
23-
director.buildMinimalViableProduct();
24-
Console.WriteLine(builder.GetProduct().ListParts());
25-
26-
Console.WriteLine("Standart full featured product:");
27-
director.buildFullFeaturedProduct();
28-
Console.WriteLine(builder.GetProduct().ListParts());
29-
30-
Console.WriteLine("Custom product:");
31-
builder.BuildPartA();
32-
builder.BuildPartC();
33-
Console.WriteLine(builder.GetProduct().ListParts());
49+
this.Reset();
3450
}
35-
}
36-
37-
public class Director
38-
{
39-
Builder builder;
40-
41-
public Director(Builder builder)
51+
52+
public void Reset()
4253
{
43-
this.builder = builder;
54+
this._product = new Product();
4455
}
45-
46-
public void buildMinimalViableProduct()
56+
57+
// EN: All production steps work with the same product instance.
58+
//
59+
// RU: Все этапы производства работают с одним и тем же экземпляром
60+
// продукта.
61+
public void BuildPartA()
4762
{
48-
builder.BuildPartA();
63+
this._product.Add("PartA1");
4964
}
5065

51-
public void buildFullFeaturedProduct()
66+
public void BuildPartB()
5267
{
53-
builder.BuildPartA();
54-
builder.BuildPartB();
55-
builder.BuildPartC();
68+
this._product.Add("PartB1");
5669
}
57-
}
58-
59-
public abstract class Builder
60-
{
61-
public abstract void BuildPartA();
62-
63-
public abstract void BuildPartB();
6470

65-
public abstract void BuildPartC();
71+
public void BuildPartC()
72+
{
73+
this._product.Add("PartC1");
74+
}
6675

67-
public abstract Product GetProduct();
68-
}
76+
// EN: Concrete Builders are supposed to provide their own methods for
77+
// retrieving results. That's because various types of builders may
78+
// create entirely different products that don't follow the same
79+
// interface. Therefore, such methods cannot be declared in the base
80+
// Builder interface (at least in a statically typed programming
81+
// language).
82+
//
83+
// Usually, after returning the end result to the client, a builder
84+
// instance is expected to be ready to start producing another product.
85+
// That's why it's a usual practice to call the reset method at the end
86+
// of the `GetProduct` method body. However, this behavior is not
87+
// mandatory, and you can make your builders wait for an explicit reset
88+
// call from the client code before disposing of the previous result.
89+
//
90+
// RU: Конкретные Строители должны предоставить свои собственные методы
91+
// получения результатов. Это связано с тем, что различные типы
92+
// строителей могут создавать совершенно разные продукты с разными
93+
// интерфейсами. Поэтому такие методы не могут быть объявлены в базовом
94+
// интерфейсе Строителя (по крайней мере, в статически типизированном
95+
// языке программирования).
96+
//
97+
// Как правило, после возвращения конечного результата клиенту,
98+
// экземпляр строителя должен быть готов к началу производства
99+
// следующего продукта. Поэтому обычной практикой является вызов метода
100+
// сброса в конце тела метода GetProduct. Однако такое поведение не
101+
// является обязательным, вы можете заставить своих строителей ждать
102+
// явного запроса на сброс из кода клиента, прежде чем избавиться от
103+
// предыдущего результата.
104+
public Product GetProduct()
105+
{
106+
Product result = this._product;
107+
108+
this.Reset();
69109

110+
return result;
111+
}
112+
}
113+
114+
// EN: It makes sense to use the Builder pattern only when your products are
115+
// quite complex and require extensive configuration.
116+
//
117+
// Unlike in other creational patterns, different concrete builders can
118+
// produce unrelated products. In other words, results of various builders
119+
// may not always follow the same interface.
120+
//
121+
// RU: Имеет смысл использовать паттерн Строитель только тогда, когда ваши
122+
// продукты достаточно сложны и требуют обширной конфигурации.
123+
//
124+
// В отличие от других порождающих паттернов, различные конкретные строители
125+
// могут производить несвязанные продукты. Другими словами, результаты
126+
// различных строителей могут не всегда следовать одному и тому же
127+
// интерфейсу.
70128
public class Product
71129
{
72-
List<object> parts = new List<object>();
130+
private List<object> _parts = new List<object>();
73131

74132
public void Add(string part)
75133
{
76-
parts.Add(part);
134+
this._parts.Add(part);
77135
}
78136

79137
public string ListParts()
80138
{
81139
string str = string.Empty;
82140

83-
for (int i = 0; i < parts.Count; i++)
141+
for (int i = 0; i < this._parts.Count; i++)
84142
{
85-
str += parts[i] + ", ";
143+
str += this._parts[i] + ", ";
86144
}
87145

88146
str = str.Remove(str.Length - 2); // removing last ",c"
89147

90148
return "Product parts: " + str + "\n";
91149
}
92150
}
93-
94-
public class ConcreteBuilder : Builder
151+
152+
// EN: The Director is only responsible for executing the building steps in
153+
// a particular sequence. It is helpful when producing products according to
154+
// a specific order or configuration. Strictly speaking, the Director class
155+
// is optional, since the client can control builders directly.
156+
//
157+
// RU: Директор отвечает только за выполнение шагов построения в
158+
// определённой последовательности. Это полезно при производстве продуктов в
159+
// определённом порядке или особой конфигурации. Строго говоря, класс
160+
// Директор необязателен, так как клиент может напрямую управлять
161+
// строителями.
162+
public class Director
95163
{
96-
Product product = new Product();
97-
98-
public override void BuildPartA()
164+
private Builder _builder;
165+
166+
public Builder Builder
99167
{
100-
product.Add("PartA1");
168+
set { _builder = value; }
101169
}
102-
103-
public override void BuildPartB()
170+
171+
// EN: The Director can construct several product variations using the same
172+
// building steps.
173+
//
174+
// RU: Директор может строить несколько вариаций продукта, используя
175+
// одинаковые шаги построения.
176+
public void buildMinimalViableProduct()
104177
{
105-
product.Add("PartB1");
178+
this._builder.BuildPartA();
106179
}
107180

108-
public override void BuildPartC()
181+
public void buildFullFeaturedProduct()
109182
{
110-
product.Add("PartC1");
183+
this._builder.BuildPartA();
184+
this._builder.BuildPartB();
185+
this._builder.BuildPartC();
111186
}
112-
113-
public override Product GetProduct()
187+
}
188+
189+
public class Client
190+
{
191+
// EN: The client code creates a builder object, passes it to the
192+
// director and then initiates the construction process. The end result
193+
// is retrieved from the builder object.
194+
//
195+
// RU: Клиентский код создаёт объект-строитель, передаёт его директору,
196+
// а затем инициирует процесс построения. Конечный результат
197+
// извлекается из объекта-строителя.
198+
public void ClientCode(Director director)
114199
{
115-
Product result = product;
200+
var builder = new ConcreteBuilder();
201+
director.Builder = builder;
202+
203+
Console.WriteLine("Standard basic product:");
204+
director.buildMinimalViableProduct();
205+
Console.WriteLine(builder.GetProduct().ListParts());
116206

117-
this.Reset();
207+
Console.WriteLine("Standard full featured product:");
208+
director.buildFullFeaturedProduct();
209+
Console.WriteLine(builder.GetProduct().ListParts());
118210

119-
return result;
211+
// EN: Remember, the Builder pattern can be used without a Director
212+
// class.
213+
//
214+
// RU: Помните, что паттерн Строитель можно использовать без класса
215+
// Директор.
216+
Console.WriteLine("Custom product:");
217+
builder.BuildPartA();
218+
builder.BuildPartC();
219+
Console.Write(builder.GetProduct().ListParts());
120220
}
121-
122-
public void Reset()
221+
}
222+
223+
class Program
224+
{
225+
static void Main(string[] args)
123226
{
124-
product = new Product();
227+
var client = new Client();
228+
var director = new Director();
229+
client.ClientCode(director);
125230
}
126231
}
127232
}

0 commit comments

Comments
 (0)