建造者模式练习——电脑组装、导演套餐与链式调用
按《Python 设计模式——建造者模式》的建议,通过三道练习巩固:① 电脑建造者(分步 set + build,链式调用);② 带导演的套餐(高配机/办公机);③ 带可选步骤的建造者(如显卡)。每步都有完整可运行代码和验证要点。
练习一:电脑建造者(分步组装 + 链式调用)
目的
体会建造者把复杂对象(电脑)的构建拆成多步(set_cpu、set_memory、set_disk),最后 build() 返回产品;每个 set 方法 return self,支持链式调用。
要求
- 定义产品 Computer:有属性 cpu、memory、disk(均为 str,默认 None);实现 str,返回类似
"CPU:xx | 内存:xx | 硬盘:xx"。 - 定义建造者 ComputerBuilder:内部持有一个 Computer 实例;提供 set_cpu(cpu)、set_memory(memory)、set_disk(disk),每个方法设置对应属性并 return self;提供 build(),返回当前组装好的 Computer,并将内部 Computer 重置为新实例(便于建造者复用)。
- 客户代码:用链式调用 builder.set_cpu(“i7”).set_memory(“16G”).set_disk(“512G”).build() 得到一台电脑,打印该电脑的 str,验证内容正确;再不设显卡,确认 str 中不出现显卡(或只出现 CPU/内存/硬盘)。
参考答案
class Computer:
def __init__(self):
self.cpu = None
self.memory = None
self.disk = None
def __str__(self):
return f"CPU:{self.cpu} | 内存:{self.memory} | 硬盘:{self.disk}"
class ComputerBuilder:
def __init__(self):
self._computer = Computer()
def set_cpu(self, cpu: str):
self._computer.cpu = cpu
return self
def set_memory(self, memory: str):
self._computer.memory = memory
return self
def set_disk(self, disk: str):
self._computer.disk = disk
return self
def build(self):
computer = self._computer
self._computer = Computer()
return computer
# 使用
builder = ComputerBuilder()
pc = builder.set_cpu("i7").set_memory("16G").set_disk("512G").build()
print(pc) # CPU:i7 | 内存:16G | 硬盘:512G
验证要点
- str(pc) 包含 CPU:i7、内存:16G、硬盘:512G。
- 客户代码是链式调用,没有多行 set;确认每个 set 方法都 return self。
- build() 返回的是新组装好的产品;若再调 builder.build() 不先 set,会得到一台“空”电脑(cpu/memory/disk 均为 None),说明 build 后内部已重置。
练习二:带导演的套餐(高配机 / 办公机)
目的
导演持有建造者,按固定顺序调用建造者的步骤,提供“套餐”方法(如 build_high_end、build_office);调用方只选套餐,不关心先 set_cpu 还是 set_memory。
要求
- 在练习一的基础上,保留 Computer、ComputerBuilder(可增加 set_gpu 以便高配机带显卡)。
- 定义 Director:构造时接收一个 ComputerBuilder;提供 build_high_end(),内部按顺序 set_cpu(“i9”)、set_memory(“32G”)、set_disk(“1T”)、set_gpu(“RTX4080”)(若建造者有 set_gpu),然后 return builder.build();提供 build_office(),内部 set_cpu(“i5”)、set_memory(“8G”)、set_disk(“256G”),不设显卡,然后 return builder.build()。
- 客户代码:创建 Builder 和 Director,分别调用 director.build_high_end() 和 director.build_office(),验证得到两台不同配置的电脑并打印。
参考答案
class Computer:
def __init__(self):
self.cpu = None
self.memory = None
self.disk = None
self.gpu = None
def __str__(self):
parts = [f"CPU:{self.cpu}", f"内存:{self.memory}", f"硬盘:{self.disk}"]
if self.gpu:
parts.append(f"显卡:{self.gpu}")
return " | ".join(parts)
class ComputerBuilder:
def __init__(self):
self._computer = Computer()
def set_cpu(self, cpu: str):
self._computer.cpu = cpu
return self
def set_memory(self, memory: str):
self._computer.memory = memory
return self
def set_disk(self, disk: str):
self._computer.disk = disk
return self
def set_gpu(self, gpu: str):
self._computer.gpu = gpu
return self
def build(self):
computer = self._computer
self._computer = Computer()
return computer
class Director:
def __init__(self, builder: ComputerBuilder):
self._builder = builder
def build_high_end(self):
return (self._builder
.set_cpu("i9")
.set_memory("32G")
.set_disk("1T")
.set_gpu("RTX4080")
.build())
def build_office(self):
return (self._builder
.set_cpu("i5")
.set_memory("8G")
.set_disk("256G")
.build())
# 使用
builder = ComputerBuilder()
director = Director(builder)
high_end = director.build_high_end()
office = director.build_office()
print(high_end) # CPU:i9 | 内存:32G | 硬盘:1T | 显卡:RTX4080
print(office) # CPU:i5 | 内存:8G | 硬盘:256G
验证要点
- build_high_end() 得到的电脑包含 i9、32G、1T、RTX4080。
- build_office() 得到的电脑包含 i5、8G、256G,且无显卡(或不出现 gpu 字段)。
- 确认:客户只调 director.build_high_end() / build_office(),不关心内部先 set 哪一项;流程封装在导演里。
练习三:带可选步骤的建造者(显卡可选)
目的
建造者中有可选步骤(如 set_gpu):调用就设置,不调用就不设置;产品在 str 或展示时对“未设置”的字段做区分(如不显示或显示“无”)。体会按需调用步骤、避免构造函数参数爆炸。
要求
- 产品 Computer 有 cpu、memory、disk、gpu;str 中若 gpu 为 None 则不拼接“显卡”部分(或显示“无显卡”)。
- 建造者 ComputerBuilder 提供 set_cpu、set_memory、set_disk、set_gpu(可选),均 return self;build() 返回当前 Computer 并重置内部产品。
- 客户代码:用同一建造者先造一台带显卡的电脑(set_gpu(“RTX3060”)),再造一台不带显卡的电脑(不调 set_gpu),分别打印两台电脑,验证第一台有显卡、第二台无显卡。
参考答案
class Computer:
def __init__(self):
self.cpu = None
self.memory = None
self.disk = None
self.gpu = None
def __str__(self):
parts = [f"CPU:{self.cpu}", f"内存:{self.memory}", f"硬盘:{self.disk}"]
if self.gpu:
parts.append(f"显卡:{self.gpu}")
else:
parts.append("无显卡")
return " | ".join(parts)
class ComputerBuilder:
def __init__(self):
self._computer = Computer()
def set_cpu(self, cpu: str):
self._computer.cpu = cpu
return self
def set_memory(self, memory: str):
self._computer.memory = memory
return self
def set_disk(self, disk: str):
self._computer.disk = disk
return self
def set_gpu(self, gpu: str):
self._computer.gpu = gpu
return self
def build(self):
computer = self._computer
self._computer = Computer()
return computer
# 使用
builder = ComputerBuilder()
pc1 = builder.set_cpu("i7").set_memory("16G").set_disk("512G").set_gpu("RTX3060").build()
pc2 = builder.set_cpu("i5").set_memory("8G").set_disk("256G").build() # 不设显卡
print(pc1) # 含 显卡:RTX3060
print(pc2) # 含 无显卡
验证要点
- pc1 的 str 中包含 显卡:RTX3060;pc2 的 str 中为 无显卡(或没有“显卡”字段)。
- 确认:可选步骤通过“调不调 set_gpu”控制,不需要在构造函数里传 gpu=None 等一长串参数。
三步汇总与自检
| 练习 | 重点 | 关键点 |
|---|---|---|
| 一 | 建造者 + 链式调用 | set 方法 return self;build() 返回产品并可重置内部;链式 set_cpu().set_memory().build()。 |
| 二 | 导演 + 套餐 | 导演持有建造者,封装固定流程;客户只调 build_high_end()/build_office()。 |
| 三 | 可选步骤 | 需要才调 set_gpu,不调则产品中该字段为 None;按需组装,避免参数爆炸。 |
自检问题
-
建造者的 set 方法为什么要 return self?
为了支持链式调用:builder.set_cpu("i7").set_memory("16G").build(),调用方写起来简洁,不必每行单独写一句 set。 -
build() 之后为什么要重置内部的 _computer?
若建造者会被多次使用(连续造多台电脑),重置后下一次 set 不会改到已返回的那台电脑;若建造者只用一次,也可以不重置,按需求选择。 -
导演和直接使用建造者的区别?
导演封装固定套餐(如高配、办公),客户只选套餐;直接使用建造者可以自由选择调哪些步骤、调几次,更灵活。两者可并存:要套餐用导演,要自定义用建造者。
做完以上三道练习,再对照《建造者模式》文档,对建造者、链式调用、导演和可选步骤会掌握得比较扎实。建议先写电脑建造者与链式调用,再加导演套餐,最后体会可选步骤,这样对建造者模式会掌握得比较扎实。