文本是《设计模式(共3篇)》专题的第 3 篇。阅读本文前,建议先阅读前面的文章:
建造者模式详解
1️⃣ 概念
定义: 将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。
特征: 用户只需指定建造的类型就可以得到他们,建造过程及细节不需要知道。
类型: 创建型
2️⃣ 适用场景
- 如果一个对象有非常复杂的内部结构(例如有很多属性)
- 想把复杂对象的创建和使用分离
3️⃣ 优点
- 封装性好,创建和使用分离
- 扩展性好,建造类之间独立,一定程度上解耦
4️⃣ 缺点
- 产生多余的Builder对象
- 产品内部发生变化,建造者都要修改,成本较大
5️⃣ 建造者模式与工厂模式的区别
- 关注点不同: 建造者模式注重于方法的调用顺序,而工厂模式注重于创建产品
- 创建对象的粒度不同: 建造者模式可以创建一些复杂的产品,由各种复杂的部件组成;工厂模式创建出来的对象都是一个样子的
- 细节层面不同: 工厂模式关注的是主要把这个对象创建出来就OK了,建造者模式创建产品的时候还需要知道创建出的这个产品是由哪些部件组成的
6️⃣ 建造者模式 Python实现
我们以攒电脑为例来演示建造者模式的实现。
① 声明抽象的Builder类
from abc import ABC, abstractmethod
class Builder(ABC):
@abstractmethod
def build_cpu(self, cpu):
pass
@abstractmethod
def build_main_board(self, main_board):
pass
@abstractmethod
def build_hard_disk(self, hard_disk):
pass
@abstractmethod
def build_display_card(self, display_card):
pass
@abstractmethod
def build_power(self, power):
pass
@abstractmethod
def build_memory(self, memory):
pass
@abstractmethod
def create_computer(self):
pass
② 声明电脑实体类Computer
class Computer:
def __init__(self):
self.cpu = None
self.main_board = None
self.hard_disk = None
self.display_card = None
self.power = None
self.memory = None
def get_cpu(self):
return self.cpu
def set_cpu(self, cpu):
self.cpu = cpu
def get_main_board(self):
return self.main_board
def set_main_board(self, main_board):
self.main_board = main_board
def get_hard_disk(self):
return self.hard_disk
def set_hard_disk(self, hard_disk):
self.hard_disk = hard_disk
def get_display_card(self):
return self.display_card
def set_display_card(self, display_card):
self.display_card = display_card
def get_power(self):
return self.power
def set_power(self, power):
self.power = power
def get_memory(self):
return self.memory
def set_memory(self, memory):
self.memory = memory
def __str__(self):
return f"Computer(cpu='{self.cpu}', main_board='{self.main_board}', " \
f"hard_disk='{self.hard_disk}', display_card='{self.display_card}', " \
f"power='{self.power}', memory='{self.memory}')"
③ 声明ActualBuilder类来继承Builder
class ActualBuilder(Builder):
def __init__(self):
self.computer = Computer()
def build_cpu(self, cpu):
self.computer.set_cpu(cpu)
def build_main_board(self, main_board):
self.computer.set_main_board(main_board)
def build_hard_disk(self, hard_disk):
self.computer.set_hard_disk(hard_disk)
def build_display_card(self, display_card):
self.computer.set_display_card(display_card)
def build_power(self, power):
self.computer.set_power(power)
def build_memory(self, memory):
self.computer.set_memory(memory)
def create_computer(self):
return self.computer
④ 创建DirectorBoss类
class DirectorBoss:
def __init__(self):
self.builder = None
def set_builder(self, builder):
self.builder = builder
def create_computer(self, cpu, main_board, hard_disk, display_card, power, memory):
self.builder.build_cpu(cpu)
self.builder.build_main_board(main_board)
self.builder.build_hard_disk(hard_disk)
self.builder.build_display_card(display_card)
self.builder.build_power(power)
self.builder.build_memory(memory)
return self.builder.create_computer()
⑤ 创建测试代码
if __name__ == "__main__":
builder = ActualBuilder()
director_boss = DirectorBoss()
director_boss.set_builder(builder)
computer = director_boss.create_computer("酷睿I7", "华硕主板", "希捷2T硬盘",
"英伟达显卡", "长城电源", "威刚内存条8G")
print(computer)
7️⃣ 建造者 Python实现 演进
以上的代码实例存在一些缺陷,首先DirectorBoss并不是必需的,另外create_computer方法的入参较多很容易出错,所以我们对建造者的实例进行演进。
① 创建优化后的Computer类
class Computer:
def __init__(self, computer_builder):
self.cpu = computer_builder.cpu
self.main_board = computer_builder.main_board
self.hard_disk = computer_builder.hard_disk
self.display_card = computer_builder.display_card
self.power = computer_builder.power
self.memory = computer_builder.memory
def __str__(self):
return f"Computer(cpu='{self.cpu}', main_board='{self.main_board}', " \
f"hard_disk='{self.hard_disk}', display_card='{self.display_card}', " \
f"power='{self.power}', memory='{self.memory}')"
class ComputerBuilder:
def __init__(self):
self.cpu = None
self.main_board = None
self.hard_disk = None
self.display_card = None
self.power = None
self.memory = None
def build_cpu(self, cpu):
self.cpu = cpu
return self
def build_main_board(self, main_board):
self.main_board = main_board
return self
def build_hard_disk(self, hard_disk):
self.hard_disk = hard_disk
return self
def build_display_card(self, display_card):
self.display_card = display_card
return self
def build_power(self, power):
self.power = power
return self
def build_memory(self, memory):
self.memory = memory
return self
def build(self):
return Computer(self)
② 创建优化后的测试代码
if __name__ == "__main__":
computer = Computer.ComputerBuilder() \
.build_cpu("酷睿I7") \
.build_main_board("华硕主板") \
.build()
print(computer)
# Python中类似Google Guava的ImmutableSet的用法
immutable_set = frozenset(['a', 'b'])
print(immutable_set)
8️⃣ 建造者模式的实际应用
① 在Python标准库中的应用
Python的字符串拼接虽然不像Java的StringBuilder,但可以使用类似的模式:
class StringBuilder:
def __init__(self):
self._strings = []
def append(self, obj):
self._strings.append(str(obj))
return self
def append_string(self, string):
self._strings.append(string)
return self
def append_char(self, char):
self._strings.append(char)
return self
def append_bool(self, boolean):
self._strings.append(str(boolean))
return self
def __str__(self):
return ''.join(self._strings)
def build(self):
return ''.join(self._strings)
# 使用示例
result = StringBuilder() \
.append("Hello") \
.append_string(" ") \
.append("World") \
.append_bool(True) \
.build()
print(result) # HelloWorldTrue
② 建造者模式在Flask中的应用
Flask框架中的应用构建也使用了类似的模式:
from flask import Flask
class FlaskAppBuilder:
def __init__(self):
self.app = Flask(__name__)
self.config = {}
self.blueprints = []
def set_config(self, key, value):
self.config[key] = value
return self
def add_blueprint(self, blueprint):
self.blueprints.append(blueprint)
return self
def set_debug(self, debug):
self.config['DEBUG'] = debug
return self
def set_secret_key(self, secret_key):
self.config['SECRET_KEY'] = secret_key
return self
def build(self):
# 应用配置
for key, value in self.config.items():
self.app.config[key] = value
# 注册蓝图
for blueprint in self.blueprints:
self.app.register_blueprint(blueprint)
return self.app
# 使用示例
# app = FlaskAppBuilder() \
# .set_debug(True) \
# .set_secret_key('your-secret-key') \
# .set_config('DATABASE_URL', 'sqlite:///app.db') \
# .add_blueprint(some_blueprint) \
# .build()
③ 建造者模式在Django中的应用
Django的QuerySet也采用了类似的链式调用模式:
# Django ORM的链式调用示例(概念展示)
class QuerySetBuilder:
def __init__(self, model):
self.model = model
self.conditions = []
self.order_fields = []
self.limit_num = None
def filter(self, **kwargs):
self.conditions.append(('filter', kwargs))
return self
def exclude(self, **kwargs):
self.conditions.append(('exclude', kwargs))
return self
def order_by(self, *fields):
self.order_fields.extend(fields)
return self
def limit(self, num):
self.limit_num = num
return self
def build(self):
# 这里会构建实际的查询
query_info = {
'model': self.model,
'conditions': self.conditions,
'order_fields': self.order_fields,
'limit': self.limit_num
}
return query_info
# 使用示例
# query = QuerySetBuilder(User) \
# .filter(age__gte=18) \
# .exclude(is_active=False) \
# .order_by('-created_at') \
# .limit(10) \
# .build()