forked from Volodichev/patterns
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuilder.py
More file actions
163 lines (126 loc) · 6.64 KB
/
builder.py
File metadata and controls
163 lines (126 loc) · 6.64 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
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any
class Builder(ABC):
"""
Интерфейс Строителя объявляет создающие методы для различных частей объектов
Продуктов.
"""
@property
@abstractmethod
def product(self) -> None:
pass
@abstractmethod
def produce_part_a(self) -> None:
pass
@abstractmethod
def produce_part_b(self) -> None:
pass
@abstractmethod
def produce_part_c(self) -> None:
pass
class ConcreteBuilder1(Builder):
"""
Классы Конкретного Строителя следуют интерфейсу Строителя и предоставляют
конкретные реализации шагов построения. Ваша программа может иметь несколько
вариантов Строителей, реализованных по-разному.
"""
def __init__(self) -> None:
"""
Новый экземпляр строителя должен содержать пустой объект продукта,
который используется в дальнейшей сборке.
"""
self.reset()
def reset(self) -> None:
self._product = Product1()
@property
def product(self) -> Product1:
"""
Конкретные Строители должны предоставить свои собственные методы
получения результатов. Это связано с тем, что различные типы строителей
могут создавать совершенно разные продукты с разными интерфейсами.
Поэтому такие методы не могут быть объявлены в базовом интерфейсе
Строителя (по крайней мере, в статически типизированном языке
программирования).
Как правило, после возвращения конечного результата клиенту, экземпляр
строителя должен быть готов к началу производства следующего продукта.
Поэтому обычной практикой является вызов метода сброса в конце тела
метода getProduct. Однако такое поведение не является обязательным, вы
можете заставить своих строителей ждать явного запроса на сброс из кода
клиента, прежде чем избавиться от предыдущего результата.
"""
product = self._product
self.reset()
return product
def produce_part_a(self) -> None:
self._product.add("PartA1")
def produce_part_b(self) -> None:
self._product.add("PartB1")
def produce_part_c(self) -> None:
self._product.add("PartC1")
class Product1():
"""
Имеет смысл использовать паттерн Строитель только тогда, когда ваши продукты
достаточно сложны и требуют обширной конфигурации.
В отличие от других порождающих паттернов, различные конкретные строители
могут производить несвязанные продукты. Другими словами, результаты
различных строителей могут не всегда следовать одному и тому же интерфейсу.
"""
def __init__(self) -> None:
self.parts = []
def add(self, part: Any) -> None:
self.parts.append(part)
def list_parts(self) -> None:
print(f"Product parts: {', '.join(self.parts)}", end="")
class Director:
"""
Директор отвечает только за выполнение шагов построения в определённой
последовательности. Это полезно при производстве продуктов в определённом
порядке или особой конфигурации. Строго говоря, класс Директор необязателен,
так как клиент может напрямую управлять строителями.
"""
def __init__(self) -> None:
self._builder = None
@property
def builder(self) -> Builder:
return self._builder
@builder.setter
def builder(self, builder: Builder) -> None:
"""
Директор работает с любым экземпляром строителя, который передаётся ему
клиентским кодом. Таким образом, клиентский код может изменить конечный
тип вновь собираемого продукта.
"""
self._builder = builder
"""
Директор может строить несколько вариаций продукта, используя одинаковые
шаги построения.
"""
def build_minimal_viable_product(self) -> None:
self.builder.produce_part_a()
def build_full_featured_product(self) -> None:
self.builder.produce_part_a()
self.builder.produce_part_b()
self.builder.produce_part_c()
if __name__ == "__main__":
"""
Клиентский код создаёт объект-строитель, передаёт его директору, а затем
инициирует процесс построения. Конечный результат извлекается из объекта-
строителя.
"""
director = Director()
builder = ConcreteBuilder1()
director.builder = builder
print("Standard basic product: ")
director.build_minimal_viable_product()
builder.product.list_parts()
print("\n")
print("Standard full featured product: ")
director.build_full_featured_product()
builder.product.list_parts()
print("\n")
# Помните, что паттерн Строитель можно использовать без класса Директор.
print("Custom product: ")
builder.produce_part_a()
builder.produce_part_b()
builder.product.list_parts()