Python建造者模式彻底搞懂|从烂代码重构到企业项目实战,小白也能上手

前言
很多Python开发者写业务代码时都会遇到一类非常头疼的问题:一个对象属性十几个,有必填参数、大量可选参数,直接写__init__构造函数,参数列表会写得很长,参数顺序稍微写错一个,程序直接出现BUG,代码可读性几乎为零。
很多新人第一反应是疯狂写if-else、写大量set方法,代码越堆越乱,后期维护几乎无从下手。而建造者模式就是专门用来解决复杂对象分步构建问题的经典创建型设计模式,不管是爬虫请求配置、SQL拼接、大数据任务参数、接口返回复杂DTO,企业项目到处都有它的身影。
本文避开晦涩难懂的理论,从实际开发痛点入手,讲清楚建造者模式原理、演进过程、生活案例、两种主流实现方式、企业实战代码、高频面试题,看完直接就能写到项目里面。
文章目录
- Python建造者模式彻底搞懂|从烂代码重构到企业项目实战,小白也能上手
-
- 前言
- 一、开发中真实痛点场景
-
- 痛点写法1:超长构造函数
- 痛点写法2:使用大量set方法
- 痛点写法3:使用字典传参
- 二、建造者模式是什么
-
- 专业解释
- 大白话解释
- 生活案例
- 三、为什么要用建造者模式(演进过程)
-
- 第一阶段:直接new对象
- 第二阶段:使用set方法
- 第三阶段:使用建造者模式
- 建造者模式的优点
- 建造者模式的缺点
- 四、建造者模式的四大角色
-
- 角色1:Product(产品)
- 角色2:Builder(抽象建造者)
- 角色3:ConcreteBuilder(具体建造者)
- 角色4:Director(指挥者)
- 使用示例
- 五、Python中更优雅的实现:链式调用建造者
-
- 基础版链式建造者
- 使用示例
- 进阶版:使用dataclass简化
- 六、企业项目实战场景
-
- 实战场景1:HTTP请求构建器
- 实战场景2:SQL查询构建器
- 实战场景3:配置对象构建器
- 实战场景4:邮件构建器
- 七、建造者模式 vs 工厂模式 vs 抽象工厂模式
-
- 一句话区分
- 代码对比
- 八、面试官高频面试题
-
- 面试题1:什么是建造者模式?它的核心思想是什么?
- 面试题2:建造者模式和工厂模式有什么区别?
- 面试题3:建造者模式的四个角色是什么?各自的职责是什么?
- 面试题4:什么时候应该使用建造者模式?
- 面试题5:建造者模式有什么优缺点?
- 面试题6:Python中如何实现链式调用的建造者模式?
- 面试题7:建造者模式中的Director角色一定要有吗?
- 面试题8:StringBuilder是不是建造者模式?
- 九、常用场景总结
-
- 不适合使用建造者模式的场景
- 十、总结
一、开发中真实痛点场景
假设现在我们需要创建一台电脑配置对象,一台电脑包含CPU、内存、硬盘、显卡、显示器、操作系统6个属性。
痛点写法1:超长构造函数
# 糟糕写法:超长参数列表
class Computer:
def __init__(self, cpu, ram, disk, gpu, monitor, os):
self.cpu = cpu
self.ram = ram
self.disk = disk
self.gpu = gpu
self.monitor = monitor
self.os = os
# 创建游戏电脑
pc = Computer("i9-14900K", 64, 2000, "RTX-4090", "32寸4K", "win11")
# 创建办公电脑
office_pc = Computer("i5-13400", 16, 512, "核显", "24寸1080P", "win10")
存在问题:
痛点写法2:使用大量set方法
class Computer:
def __init__(self):
self.cpu = None
self.ram = None
self.disk = None
def set_cpu(self, cpu):
self.cpu = cpu
def set_ram(self, ram):
self.ram = ram
pc = Computer()
pc.set_cpu("i9")
pc.set_ram(32)
存在问题:
痛点写法3:使用字典传参
class Computer:
def __init__(self, config: dict):
self.cpu = config.get("cpu")
self.ram = config.get("ram")
self.disk = config.get("disk")
pc = Computer({"cpu": "i9", "ram": 32, "disk": 1000})
存在问题:
这三种写法是不是非常熟悉?几乎每个Python开发者都写过这样的代码。那么有没有一种优雅的方式来解决这些问题呢?答案就是建造者模式。
二、建造者模式是什么
专业解释
建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
核心思想是:将一个复杂对象的创建过程拆分成多个简单的步骤,通过一步步组装来完成对象的创建。用户只需要指定需要构建的类型和内容,不需要知道内部的具体构建细节。
建造者模式通常包含四个角色:
大白话解释
说人话就是:造一个东西太复杂了,步骤太多,那就把造东西的过程拆成一步一步来,每一步只干一件事,最后一步统一组装出成品。
就像去肯德基点套餐,你不需要知道汉堡怎么做、可乐怎么调,你只需要告诉服务员你要A套餐还是B套餐,服务员(指挥者)会按照固定流程(建造者)一步步把汉堡、可乐、薯条组装好(产品)递给你。
生活案例
案例1:肯德基套餐
去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的套餐。牛肉汉堡+可口可乐=肥牛套餐,鸡肉汉堡+百事可乐=炸鸡套餐,同样的构建步骤(选汉堡+选饮料),不同的表示(不同的汉堡和饮料)。
案例2:组装电脑
买电脑时,CPU、内存、硬盘、显卡、显示器这些部件是固定的组装步骤,但每个部件可以选择不同品牌和型号。游戏玩家选i9+RTX4090,办公用户选i5+核显,同样的组装流程,不同的配置方案。
案例3:奶茶定制
点奶茶时,固定步骤是选茶底、选甜度、选温度、加料,但每个步骤可以有不同选择。同样的制作流程,可以做出无数种不同口味的奶茶。
三、为什么要用建造者模式(演进过程)
第一阶段:直接new对象
最原始的方式,直接实例化对象,所有参数通过构造函数传入。当对象属性少的时候没问题,属性一多就灾难了。
# 属性少的时候没问题
user = User("张三", 25)
# 属性多了之后灾难
order = Order("ORD20240101", "张三", "13800138000", "北京市朝阳区",
"商品A", 2, 99.9, "微信支付", "顺丰快递", "备注信息", ...)
第二阶段:使用set方法
为了解决构造函数参数太多的问题,开始使用无参构造+set方法的方式。但带来了新问题:对象状态不完整、可以被中途修改、无法保证构建顺序。
order = Order()
order.set_order_id("ORD20240101")
order.set_user_name("张三")
# 中间可能被其他代码修改
order.set_phone("13800138000")
第三阶段:使用建造者模式
将对象的构建过程封装到一个独立的Builder类中,通过链式调用一步步设置属性,最后调用build方法生成完整对象。既解决了参数太多的问题,又保证了对象的完整性和不可变性。
order = (OrderBuilder()
.order_id("ORD20240101")
.user_name("张三")
.phone("13800138000")
.address("北京市朝阳区")
.build())
建造者模式的优点
建造者模式的缺点

四、建造者模式的四大角色
建造者模式的标准结构包含四个核心角色,它们各司其职,共同完成复杂对象的构建。

角色1:Product(产品)
最终要构建的复杂对象,包含多个组成部分。
class Computer:
"""电脑产品类"""
def __init__(self):
self.cpu = None
self.ram = None
self.disk = None
self.gpu = None
self.monitor = None
self.os = None
def __str__(self):
return (f"电脑配置:\\n"
f" CPU: {self.cpu}\\n"
f" 内存: {self.ram}GB\\n"
f" 硬盘: {self.disk}GB\\n"
f" 显卡: {self.gpu}\\n"
f" 显示器: {self.monitor}\\n"
f" 系统: {self.os}")
角色2:Builder(抽象建造者)
定义构建产品各个部件的抽象接口,规定了构建复杂对象需要哪些步骤。
from abc import ABC, abstractmethod
class ComputerBuilder(ABC):
"""电脑建造者抽象类"""
def __init__(self):
self.computer = Computer()
@abstractmethod
def build_cpu(self):
"""构建CPU"""
pass
@abstractmethod
def build_ram(self):
"""构建内存"""
pass
@abstractmethod
def build_disk(self):
"""构建硬盘"""
pass
@abstractmethod
def build_gpu(self):
"""构建显卡"""
pass
@abstractmethod
def build_monitor(self):
"""构建显示器"""
pass
@abstractmethod
def build_os(self):
"""构建操作系统"""
pass
def get_computer(self):
"""获取构建完成的电脑"""
return self.computer
角色3:ConcreteBuilder(具体建造者)
实现Builder接口,具体实现每一步的构建逻辑,不同的具体建造者可以构建出不同配置的产品。
class GamingComputerBuilder(ComputerBuilder):
"""游戏电脑建造者"""
def build_cpu(self):
self.computer.cpu = "Intel i9-14900K"
def build_ram(self):
self.computer.ram = 64
def build_disk(self):
self.computer.disk = 2000
def build_gpu(self):
self.computer.gpu = "NVIDIA RTX 4090"
def build_monitor(self):
self.computer.monitor = "32寸 4K 144Hz"
def build_os(self):
self.computer.os = "Windows 11 Pro"
class OfficeComputerBuilder(ComputerBuilder):
"""办公电脑建造者"""
def build_cpu(self):
self.computer.cpu = "Intel i5-13400"
def build_ram(self):
self.computer.ram = 16
def build_disk(self):
self.computer.disk = 512
def build_gpu(self):
self.computer.gpu = "集成显卡"
def build_monitor(self):
self.computer.monitor = "24寸 1080P"
def build_os(self):
self.computer.os = "Windows 10 Home"
角色4:Director(指挥者)
负责控制构建过程的顺序,调用建造者的方法来构建产品,客户端只需要和指挥者交互。
class ComputerDirector:
"""电脑指挥者"""
def __init__(self, builder: ComputerBuilder):
self.builder = builder
def construct(self):
"""按照固定顺序构建电脑"""
self.builder.build_cpu()
self.builder.build_ram()
self.builder.build_disk()
self.builder.build_gpu()
self.builder.build_monitor()
self.builder.build_os()
return self.builder.get_computer()
使用示例
if __name__ == "__main__":
# 构建游戏电脑
gaming_builder = GamingComputerBuilder()
director = ComputerDirector(gaming_builder)
gaming_pc = director.construct()
print(gaming_pc)
print("-" * 30)
# 构建办公电脑
office_builder = OfficeComputerBuilder()
director = ComputerDirector(office_builder)
office_pc = director.construct()
print(office_pc)
输出结果:
电脑配置:
CPU: Intel i9-14900K
内存: 64GB
硬盘: 2000GB
显卡: NVIDIA RTX 4090
显示器: 32寸 4K 144Hz
系统: Windows 11 Pro
——————————
电脑配置:
CPU: Intel i5-13400
内存: 16GB
硬盘: 512GB
显卡: 集成显卡
显示器: 24寸 1080P
系统: Windows 10 Home
五、Python中更优雅的实现:链式调用建造者
上面的经典实现方式虽然规范,但在Python中略显繁琐。Python中更常用的是链式调用(Fluent Interface)风格的建造者模式,每个方法返回self,最后调用build方法生成对象。

基础版链式建造者
class Computer:
"""电脑产品类"""
def __init__(self):
self.cpu = None
self.ram = None
self.disk = None
self.gpu = None
self.monitor = None
self.os = None
def __str__(self):
return (f"电脑配置:\\n"
f" CPU: {self.cpu}\\n"
f" 内存: {self.ram}GB\\n"
f" 硬盘: {self.disk}GB\\n"
f" 显卡: {self.gpu}\\n"
f" 显示器: {self.monitor}\\n"
f" 系统: {self.os}")
class ComputerBuilder:
"""电脑建造者"""
def __init__(self):
self.computer = Computer()
def set_cpu(self, cpu: str) –> "ComputerBuilder":
self.computer.cpu = cpu
return self
def set_ram(self, ram: int) –> "ComputerBuilder":
self.computer.ram = ram
return self
def set_disk(self, disk: int) –> "ComputerBuilder":
self.computer.disk = disk
return self
def set_gpu(self, gpu: str) –> "ComputerBuilder":
self.computer.gpu = gpu
return self
def set_monitor(self, monitor: str) –> "ComputerBuilder":
self.computer.monitor = monitor
return self
def set_os(self, os: str) –> "ComputerBuilder":
self.computer.os = os
return self
def build(self) –> Computer:
"""构建完成,返回电脑对象"""
# 可以在这里做参数校验
if not self.computer.cpu:
raise ValueError("CPU不能为空")
if not self.computer.ram:
raise ValueError("内存不能为空")
return self.computer
使用示例
if __name__ == "__main__":
# 链式调用构建游戏电脑
gaming_pc = (ComputerBuilder()
.set_cpu("Intel i9-14900K")
.set_ram(64)
.set_disk(2000)
.set_gpu("NVIDIA RTX 4090")
.set_monitor("32寸 4K 144Hz")
.set_os("Windows 11 Pro")
.build())
print(gaming_pc)
print("-" * 30)
# 链式调用构建办公电脑(不需要显卡)
office_pc = (ComputerBuilder()
.set_cpu("Intel i5-13400")
.set_ram(16)
.set_disk(512)
.set_monitor("24寸 1080P")
.set_os("Windows 10 Home")
.build())
print(office_pc)
进阶版:使用dataclass简化
Python 3.7+提供了dataclass装饰器,可以大幅简化产品类的定义。
from dataclasses import dataclass, field
from typing import Optional, List
@dataclass
class Computer:
"""电脑产品类,使用dataclass简化"""
cpu: Optional[str] = None
ram: Optional[int] = None
disk: Optional[int] = None
gpu: Optional[str] = None
monitor: Optional[str] = None
os: Optional[str] = None
peripherals: List[str] = field(default_factory=list)
def __str__(self):
return (f"电脑配置:\\n"
f" CPU: {self.cpu}\\n"
f" 内存: {self.ram}GB\\n"
f" 硬盘: {self.disk}GB\\n"
f" 显卡: {self.gpu}\\n"
f" 显示器: {self.monitor}\\n"
f" 系统: {self.os}\\n"
f" 外设: {', '.join(self.peripherals) if self.peripherals else '无'}")
class ComputerBuilder:
"""电脑建造者"""
def __init__(self):
self._computer = Computer()
def cpu(self, cpu: str) –> "ComputerBuilder":
self._computer.cpu = cpu
return self
def ram(self, ram: int) –> "ComputerBuilder":
self._computer.ram = ram
return self
def disk(self, disk: int) –> "ComputerBuilder":
self._computer.disk = disk
return self
def gpu(self, gpu: str) –> "ComputerBuilder":
self._computer.gpu = gpu
return self
def monitor(self, monitor: str) –> "ComputerBuilder":
self._computer.monitor = monitor
return self
def os(self, os: str) –> "ComputerBuilder":
self._computer.os = os
return self
def add_peripheral(self, peripheral: str) –> "ComputerBuilder":
self._computer.peripherals.append(peripheral)
return self
def build(self) –> Computer:
"""构建完成,返回电脑对象"""
if not self._computer.cpu:
raise ValueError("CPU是必填项")
if not self._computer.ram or self._computer.ram < 4:
raise ValueError("内存不能小于4GB")
return self._computer
六、企业项目实战场景
建造者模式在企业项目中应用非常广泛,下面介绍几个最常见的实战场景。
实战场景1:HTTP请求构建器
在爬虫或API调用中,HTTP请求通常包含URL、方法、请求头、请求体、超时时间等多个参数,非常适合使用建造者模式。
from dataclasses import dataclass, field
from typing import Optional, Dict
import requests
@dataclass
class HttpRequest:
"""HTTP请求对象"""
url: str
method: str = "GET"
headers: Dict[str, str] = field(default_factory=dict)
params: Dict[str, str] = field(default_factory=dict)
body: Optional[str] = None
timeout: int = 30
verify_ssl: bool = True
class HttpRequestBuilder:
"""HTTP请求构建器"""
def __init__(self, url: str):
self._request = HttpRequest(url=url)
def method(self, method: str) –> "HttpRequestBuilder":
self._request.method = method.upper()
return self
def header(self, key: str, value: str) –> "HttpRequestBuilder":
self._request.headers[key] = value
return self
def headers(self, headers: Dict[str, str]) –> "HttpRequestBuilder":
self._request.headers.update(headers)
return self
def param(self, key: str, value: str) –> "HttpRequestBuilder":
self._request.params[key] = value
return self
def body(self, body: str) –> "HttpRequestBuilder":
self._request.body = body
return self
def timeout(self, timeout: int) –> "HttpRequestBuilder":
self._request.timeout = timeout
return self
def disable_ssl_verify(self) –> "HttpRequestBuilder":
self._request.verify_ssl = False
return self
def build(self) –> HttpRequest:
"""构建请求对象"""
if not self._request.url.startswith(("http://", "https://")):
raise ValueError("URL必须以http://或https://开头")
return self._request
def execute(self) –> requests.Response:
"""直接执行请求"""
req = self.build()
return requests.request(
method=req.method,
url=req.url,
headers=req.headers,
params=req.params,
data=req.body,
timeout=req.timeout,
verify=req.verify_ssl
)
使用示例:
# 构建一个POST请求
response = (HttpRequestBuilder("https://api.example.com/users")
.method("POST")
.header("Content-Type", "application/json")
.header("Authorization", "Bearer token123")
.body('{"name": "张三", "age": 25}')
.timeout(10)
.execute())
print(response.status_code)
print(response.json())
实战场景2:SQL查询构建器
在数据库操作中,复杂的SQL查询包含SELECT、FROM、WHERE、JOIN、ORDER BY、LIMIT等多个子句,使用建造者模式可以优雅地构建SQL语句,避免字符串拼接的混乱。
class SQLQueryBuilder:
"""SQL查询构建器"""
def __init__(self):
self._select = "*"
self._table = None
self._joins = []
self._where = []
self._order_by = None
self._group_by = None
self._limit = None
self._offset = None
def select(self, columns: str) –> "SQLQueryBuilder":
self._select = columns
return self
def from_table(self, table: str) –> "SQLQueryBuilder":
self._table = table
return self
def join(self, table: str, on_condition: str) –> "SQLQueryBuilder":
self._joins.append(f"JOIN {table} ON {on_condition}")
return self
def left_join(self, table: str, on_condition: str) –> "SQLQueryBuilder":
self._joins.append(f"LEFT JOIN {table} ON {on_condition}")
return self
def where(self, condition: str) –> "SQLQueryBuilder":
self._where.append(condition)
return self
def and_where(self, condition: str) –> "SQLQueryBuilder":
self._where.append(f"AND {condition}")
return self
def or_where(self, condition: str) –> "SQLQueryBuilder":
self._where.append(f"OR {condition}")
return self
def order_by(self, column: str, direction: str = "ASC") –> "SQLQueryBuilder":
self._order_by = f"ORDER BY {column} {direction}"
return self
def group_by(self, column: str) –> "SQLQueryBuilder":
self._group_by = f"GROUP BY {column}"
return self
def limit(self, limit: int) –> "SQLQueryBuilder":
self._limit = f"LIMIT {limit}"
return self
def offset(self, offset: int) –> "SQLQueryBuilder":
self._offset = f"OFFSET {offset}"
return self
def build(self) –> str:
"""构建SQL语句"""
if not self._table:
raise ValueError("必须指定表名")
query_parts = [f"SELECT {self._select}", f"FROM {self._table}"]
if self._joins:
query_parts.extend(self._joins)
if self._where:
where_clause = " WHERE " + " ".join(self._where)
query_parts.append(where_clause)
if self._group_by:
query_parts.append(self._group_by)
if self._order_by:
query_parts.append(self._order_by)
if self._limit:
query_parts.append(self._limit)
if self._offset:
query_parts.append(self._offset)
return " ".join(query_parts) + ";"
使用示例:
# 构建复杂查询
sql = (SQLQueryBuilder()
.select("u.id, u.name, u.age, o.order_no, o.amount")
.from_table("users u")
.left_join("orders o", "u.id = o.user_id")
.where("u.age > 18")
.and_where("o.amount > 100")
.order_by("o.amount", "DESC")
.limit(10)
.offset(0)
.build())
print(sql)
输出结果:
SELECT u.id, u.name, u.age, o.order_no, o.amount FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.age > 18 AND o.amount > 100 ORDER BY o.amount DESC LIMIT 10 OFFSET 0;
实战场景3:配置对象构建器
在企业项目中,数据库连接配置、Redis配置、线程池配置等通常有很多参数,使用建造者模式可以让配置更清晰。
from dataclasses import dataclass
from typing import Optional
@dataclass
class DatabaseConfig:
"""数据库配置"""
host: str
port: int
database: str
username: str
password: str
pool_size: int = 5
max_overflow: int = 10
pool_timeout: int = 30
pool_recycle: int = 3600
echo: bool = False
charset: str = "utf8mb4"
class DatabaseConfigBuilder:
"""数据库配置构建器"""
def __init__(self):
self._config = DatabaseConfig(
host="localhost",
port=3306,
database="",
username="root",
password=""
)
def host(self, host: str) –> "DatabaseConfigBuilder":
self._config.host = host
return self
def port(self, port: int) –> "DatabaseConfigBuilder":
self._config.port = port
return self
def database(self, database: str) –> "DatabaseConfigBuilder":
self._config.database = database
return self
def username(self, username: str) –> "DatabaseConfigBuilder":
self._config.username = username
return self
def password(self, password: str) –> "DatabaseConfigBuilder":
self._config.password = password
return self
def pool_size(self, size: int) –> "DatabaseConfigBuilder":
self._config.pool_size = size
return self
def max_overflow(self, overflow: int) –> "DatabaseConfigBuilder":
self._config.max_overflow = overflow
return self
def echo(self, echo: bool = True) –> "DatabaseConfigBuilder":
self._config.echo = echo
return self
def build(self) –> DatabaseConfig:
"""构建配置对象"""
if not self._config.host:
raise ValueError("数据库主机地址不能为空")
if not self._config.database:
raise ValueError("数据库名不能为空")
if self._config.pool_size < 1:
raise ValueError("连接池大小不能小于1")
return self._config
使用示例:
# 构建生产环境数据库配置
prod_config = (DatabaseConfigBuilder()
.host("192.168.1.100")
.port(3306)
.database("production_db")
.username("prod_user")
.password("prod_password")
.pool_size(20)
.max_overflow(50)
.build())
# 构建开发环境数据库配置
dev_config = (DatabaseConfigBuilder()
.host("localhost")
.database("dev_db")
.username("root")
.password("root")
.echo(True)
.build())
print(prod_config)
print(dev_config)
实战场景4:邮件构建器
发送邮件时,通常包含发件人、收件人、抄送、主题、正文、附件等多个部分,使用建造者模式可以优雅地构建邮件。
from dataclasses import dataclass, field
from typing import List, Optional
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
@dataclass
class Email:
"""邮件对象"""
sender: str
recipients: List[str] = field(default_factory=list)
cc: List[str] = field(default_factory=list)
bcc: List[str] = field(default_factory=list)
subject: str = ""
body: str = ""
content_type: str = "plain"
attachments: List[str] = field(default_factory=list)
class EmailBuilder:
"""邮件构建器"""
def __init__(self, sender: str):
self._email = Email(sender=sender)
def to(self, recipient: str) –> "EmailBuilder":
self._email.recipients.append(recipient)
return self
def to_many(self, recipients: List[str]) –> "EmailBuilder":
self._email.recipients.extend(recipients)
return self
def cc(self, cc: str) –> "EmailBuilder":
self._email.cc.append(cc)
return self
def bcc(self, bcc: str) –> "EmailBuilder":
self._email.bcc.append(bcc)
return self
def subject(self, subject: str) –> "EmailBuilder":
self._email.subject = subject
return self
def body(self, body: str) –> "EmailBuilder":
self._email.body = body
return self
def html_body(self, html: str) –> "EmailBuilder":
self._email.body = html
self._email.content_type = "html"
return self
def attachment(self, file_path: str) –> "EmailBuilder":
self._email.attachments.append(file_path)
return self
def build(self) –> Email:
"""构建邮件对象"""
if not self._email.recipients:
raise ValueError("收件人不能为空")
if not self._email.subject:
raise ValueError("邮件主题不能为空")
return self._email
def send(self, smtp_server: str, smtp_port: int, password: str):
"""发送邮件"""
email = self.build()
msg = MIMEMultipart()
msg["From"] = email.sender
msg["To"] = ", ".join(email.recipients)
if email.cc:
msg["Cc"] = ", ".join(email.cc)
msg["Subject"] = email.subject
msg.attach(MIMEText(email.body, email.content_type, "utf-8"))
all_recipients = email.recipients + email.cc + email.bcc
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls()
server.login(email.sender, password)
server.sendmail(email.sender, all_recipients, msg.as_string())
使用示例:
# 构建并发送HTML邮件
(EmailBuilder("sender@example.com")
.to("user1@example.com")
.to("user2@example.com")
.cc("manager@example.com")
.subject("项目进度报告")
.html_body("<h1>本周项目进度</h1><p>已完成80%</p>")
.attachment("/path/to/report.pdf")
.send("smtp.example.com", 587, "password"))
七、建造者模式 vs 工厂模式 vs 抽象工厂模式
这三个模式都属于创建型模式,经常被拿来对比,也是面试高频考点。

| 核心意图 | 关注创建什么,创建单一产品 | 关注创建产品族,创建一组相关产品 | 关注如何创建,分步构建复杂对象 |
| 产品复杂度 | 简单/标准化对象 | 多个相关产品组成的产品族 | 复杂对象,由多个部件组成 |
| 构建过程 | 一次性创建完成 | 一次性创建多个产品 | 分步骤构建,可以控制顺序 |
| 灵活性 | 较低,产品类型固定 | 中等,可以切换产品族 | 较高,可以自由组合部件 |
| 典型应用 | 数据库驱动创建、日志器创建 | 跨平台UI组件、多数据库访问 | SQL构建、HTTP请求构建、配置对象 |
一句话区分
- 工厂模式:我要一个苹果,工厂直接给我一个苹果
- 抽象工厂模式:我要一套苹果产品(手机+电脑+平板),工厂直接给我一整套
- 建造者模式:我要一台电脑,我一步步告诉你CPU要什么、内存要什么、硬盘要什么,最后组装好给我
代码对比
# 工厂模式:直接创建完整对象
class ComputerFactory:
@staticmethod
def create_computer(computer_type: str):
if computer_type == "gaming":
return Computer("i9", 64, 2000, "RTX4090")
elif computer_type == "office":
return Computer("i5", 16, 512, "核显")
# 抽象工厂模式:创建一整套产品
class AppleFactory:
def create_phone(self):
return IPhone()
def create_computer(self):
return Mac()
def create_tablet(self):
return IPad()
# 建造者模式:分步构建
gaming_pc = (ComputerBuilder()
.set_cpu("i9")
.set_ram(64)
.set_disk(2000)
.set_gpu("RTX4090")
.build())
八、面试官高频面试题
面试题1:什么是建造者模式?它的核心思想是什么?
参考答案:
建造者模式是一种创建型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
核心思想是将复杂对象的创建过程拆分成多个简单的步骤,通过一步步组装来完成对象的创建。用户只需要指定需要构建的内容,不需要知道内部的具体构建细节。
面试题2:建造者模式和工厂模式有什么区别?
参考答案:
面试题3:建造者模式的四个角色是什么?各自的职责是什么?
参考答案:
面试题4:什么时候应该使用建造者模式?
参考答案:
面试题5:建造者模式有什么优缺点?
参考答案:
优点:
缺点:
面试题6:Python中如何实现链式调用的建造者模式?
参考答案:
每个设置方法返回self,这样就可以连续调用多个方法,最后调用build方法返回最终对象。
class Builder:
def __init__(self):
self._product = Product()
def set_name(self, name):
self._product.name = name
return self # 关键:返回self
def set_age(self, age):
self._product.age = age
return self # 关键:返回self
def build(self):
return self._product
# 使用
product = Builder().set_name("张三").set_age(25).build()
面试题7:建造者模式中的Director角色一定要有吗?
参考答案:
不一定。在经典的建造者模式中,Director负责控制构建顺序,但在实际应用中,特别是Python的链式调用风格中,通常会省略Director角色,由客户端直接控制构建顺序。这样更加灵活,代码也更简洁。
面试题8:StringBuilder是不是建造者模式?
参考答案:
是的,StringBuilder是建造者模式的典型应用。它通过append方法一步步构建字符串,最后调用toString方法得到最终的字符串对象。每个append方法返回this(Java中)或self(Python中类似),支持链式调用。
九、常用场景总结
根据GitHub代码分析统计,建造者模式在以下场景使用率最高:
不适合使用建造者模式的场景
十、总结
建造者模式是解决复杂对象构建问题的利器,它的核心价值在于:
在Python中,推荐使用链式调用风格的建造者模式,结合dataclass可以让代码更加简洁优雅。在企业项目中,HTTP请求构建、SQL查询构建、配置对象构建、邮件构建都是建造者模式的典型应用场景。
掌握建造者模式,不仅能让你的代码更加优雅,也是面试中的高频考点。希望本文能帮助你彻底搞懂建造者模式,在实际项目中灵活运用。
转载声明:本文为原创文章,如需转载,请联系作者获得授权,并注明出处。
网硕互联帮助中心



评论前必须登录!
注册