设计模式是软件开发中解决共性问题的成熟方案,就像编程世界的 “通用模板”—— 无需重复造轮子,就能写出灵活、可维护、易扩展的代码。GoF(四人帮)定义的 23 种设计模式是行业标杆,其中不少模式在 Python 开发中高频出现。本文将聚焦最实用的设计模式,用 “生活类比 + Python 代码” 的方式拆解核心逻辑,帮你快速掌握并落地到实际项目中。
一、创建型模式:优雅管理对象创建
创建型模式的核心是 “分离对象创建与使用”,避免硬编码导致的耦合,让对象创建更灵活。
1. 单例模式:确保唯一实例
- 核心思想:一个类只能创建一个实例,同时提供全局统一的访问入口。
- 生活类比:国家只有一个首都、APP 只有一个全局配置对象,无法重复创建。
- 适用场景:数据库连接池、日志记录器、全局配置、线程池(避免资源浪费)。
- Python 实现(懒加载版):
python
运行
class Singleton:
# 私有类属性,存储唯一实例
__instance = None
def __new__(cls):
# 首次创建时初始化实例,后续直接返回已有实例
if not cls.__instance:
cls.__instance = super().__new__(cls)
# 初始化全局配置(仅执行一次)
cls.__instance.config = {"timeout": 30, "encoding": "utf-8"}
return cls.__instance
# 测试:多次实例化结果一致
obj1 = Singleton()
obj2 = Singleton()
print(obj1 is obj2) # 输出:True(同一实例)
obj1.config["timeout"] = 60
print(obj2.config["timeout"]) # 输出:60(共享属性)
2. 工厂方法模式:延迟实例化到子类
- 核心思想:定义创建对象的接口,让子类决定具体实例化哪个类,实现 “创建逻辑” 与 “使用逻辑” 分离。
- 生活类比:家具厂(父类)定义 “制作家具” 接口,椅子厂、桌子厂(子类)分别实现该接口,生产具体产品。
- 适用场景:日志输出(控制台 / 文件 / 数据库)、数据库连接(MySQL/PostgreSQL)、支付渠道对接。
- Python 实现(日志工厂):
python
运行
# 抽象产品:日志接口
class Logger:
def log(self, message):
raise NotImplementedError("子类必须实现log方法")
# 具体产品1:控制台日志
class ConsoleLogger(Logger):
def log(self, message):
print(f"[控制台] {message}")
# 具体产品2:文件日志
class FileLogger(Logger):
def log(self, message):
with open("app.log", "a", encoding="utf-8") as f:
f.write(f"[文件] {message}\n")
# 工厂方法:日志工厂
class LoggerFactory:
def create_logger(self, type_):
if type_ == "console":
return ConsoleLogger()
elif type_ == "file":
return FileLogger()
else:
raise ValueError("不支持的日志类型")
# 使用示例
factory = LoggerFactory()
console_logger = factory.create_logger("console")
file_logger = factory.create_logger("file")
console_logger.log("用户登录成功") # 控制台输出
file_logger.log("系统启动完成") # 写入文件
3. 建造者模式:分步构建复杂对象
- 核心思想:将复杂对象的构建流程与组件细节分离,相同流程可创建不同配置的对象。
- 生活类比:组装电脑,流程固定(装 CPU→内存→硬盘→显卡),但可选择不同品牌、配置的组件,最终得到高配 / 低配电脑。
- 适用场景:SQL 查询构建、邮件对象组装、复杂配置类创建。
- Python 实现(SQL 构建器):
python
运行
class SQLBuilder:
def __init__(self):
self.sql = ""
self.select_clause = ""
self.from_clause = ""
self.where_clause = ""
# 步骤1:设置查询字段
def select(self, fields):
self.select_clause = f"SELECT {','.join(fields)}"
return self # 链式调用
# 步骤2:设置表名
def from_table(self, table):
self.from_clause = f"FROM {table}"
return self
# 步骤3:设置查询条件
def where(self, condition):
self.where_clause = f"WHERE {condition}"
return self
# 步骤4:构建最终SQL
def build(self):
self.sql = f"{self.select_clause} {self.from_clause} {self.where_clause}"
return self.sql
# 使用示例:链式构建SQL
sql = SQLBuilder()\
.select(["id", "name", "age"])\
.from_table("users")\
.where("age > 18")\
.build()
print(sql) # 输出:SELECT id,name,age FROM users WHERE age > 18
二、结构型模式:灵活组合类与对象
结构型模式关注 “如何将类或对象组合成更复杂的结构”,同时保持结构的灵活性和可扩展性。
1. 适配器模式:解决接口不兼容问题
- 核心思想:将一个类的接口转换成客户端期望的另一个接口,让原本无法协作的类能够一起工作。
- 生活类比:电源转接头,中国插头(旧接口)通过转接头适配欧洲插座(新接口)。
- 适用场景:整合遗留系统、第三方库接口适配、旧代码重构。
- Python 实现(支付接口适配):
python
运行
# 第三方支付库(旧接口,无法修改)
class AlipayOld:
def pay_old(self, amount):
return f"支付宝旧接口支付 {amount} 元"
# 客户端期望的统一接口(新接口)
class PaymentInterface:
def pay(self, amount):
raise NotImplementedError("必须实现pay方法")
# 适配器:将支付宝旧接口适配到新接口
class AlipayAdapter(PaymentInterface):
def __init__(self, alipay_old):
self.alipay_old = alipay_old
def pay(self, amount):
# 适配旧接口方法到新接口
return self.alipay_old.pay_old(amount)
# 使用示例:客户端统一调用新接口
old_alipay = AlipayOld()
adapter = AlipayAdapter(old_alipay)
print(adapter.pay(100)) # 输出:支付宝旧接口支付 100 元
2. 装饰器模式:动态添加对象功能
- 核心思想:不改变原对象结构,动态给对象添加额外职责,比继承更灵活(可自由组合功能)。
- 生活类比:给手机贴钢化膜(防刮)、戴保护壳(防摔)、挂挂件(装饰),不改变手机本身,却增加了新功能。
- 适用场景:日志记录、性能监控、权限校验、数据缓存。
- Python 实现(函数装饰器):
python
运行
import time
# 装饰器1:记录函数执行日志
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"[日志] 执行函数 {func.__name__}")
result = func(*args, **kwargs)
print(f"[日志] 函数 {func.__name__} 执行完成")
return result
return wrapper
# 装饰器2:统计函数执行时间
def time_decorator(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"[耗时] 函数 {func.__name__} 执行时间:{end - start:.2f}秒")
return result
return wrapper
# 组合装饰器:给函数同时添加日志和耗时统计功能
@log_decorator
@time_decorator
def calculate_sum(n):
return sum(range(1, n+1))
# 使用示例
print(calculate_sum(1000000))
# 输出:
# [日志] 执行函数 calculate_sum
# [耗时] 函数 calculate_sum 执行时间:0.04秒
# [日志] 函数 calculate_sum 执行完成
# 500000500000
3. 外观模式:简化复杂子系统调用
- 核心思想:为复杂子系统提供一个统一的高层接口,隐藏内部细节,让客户端调用更简单。
- 生活类比:餐厅服务员,客户无需直接对接后厨、收银台、采购部,只需告诉服务员需求,由服务员协调内部流程。
- 适用场景:简化复杂库调用、遗留系统封装、微服务接口聚合。
- Python 实现(订单处理系统):
python
运行
# 复杂子系统1:库存检查
class InventoryService:
def check_stock(self, product_id, quantity):
print(f"检查商品 {product_id} 库存,需 {quantity} 件")
return True # 假设库存充足
# 复杂子系统2:支付处理
class PaymentService:
def process_payment(self, user_id, amount):
print(f"用户 {user_id} 支付 {amount} 元")
return True # 假设支付成功
# 复杂子系统3:物流下单
class LogisticsService:
def create_order(self, product_id, user_id):
print(f"为用户 {user_id} 创建商品 {product_id} 物流单")
return "物流单号:LOG123456"
# 外观类:统一订单处理接口
class OrderFacade:
def __init__(self):
self.inventory = InventoryService()
self.payment = PaymentService()
self.logistics = LogisticsService()
def place_order(self, user_id, product_id, quantity, amount):
# 协调子系统流程
if not self.inventory.check_stock(product_id, quantity):
return "库存不足,下单失败"
if not self.payment.process_payment(user_id, amount):
return "支付失败,下单失败"
logistics_no = self.logistics.create_order(product_id, user_id)
return f"下单成功!{logistics_no}"
# 使用示例:客户端只需调用外观类接口
facade = OrderFacade()
result = facade.place_order(user_id=1001, product_id=2001, quantity=2, amount=299)
print(result) # 输出:下单成功!物流单号:LOG123456
三、行为型模式:优化对象间通信与职责
行为型模式关注 “对象间的职责分配” 和 “通信方式”,让对象协作更高效、灵活。
1. 观察者模式:一对多的通知机制
- 核心思想:定义对象间的一对多依赖关系,当一个对象(主题)状态变化时,所有依赖它的对象(观察者)会自动收到通知并更新。
- 生活类比:微信公众号(主题)与订阅用户(观察者),公众号发布新文章时,所有订阅用户都会收到推送。
- 适用场景:事件驱动系统、MVC 模式(模型 – 视图)、消息通知、状态同步。
- Python 实现(消息通知系统):
python
运行
class Subject:
def __init__(self):
self.observers = [] # 存储所有观察者
# 注册观察者
def attach(self, observer):
self.observers.append(observer)
# 移除观察者
def detach(self, observer):
self.observers.remove(observer)
# 通知所有观察者
def notify(self, message):
for observer in self.observers:
observer.update(message)
# 观察者1:邮件通知
class EmailObserver:
def __init__(self, email):
self.email = email
def update(self, message):
print(f"向 {self.email} 发送邮件通知:{message}")
# 观察者2:短信通知
class SmsObserver:
def __init__(self, phone):
self.phone = phone
def update(self, message):
print(f"向 {self.phone} 发送短信通知:{message}")
# 使用示例
subject = Subject()
# 注册观察者
subject.attach(EmailObserver("user1@example.com"))
subject.attach(SmsObserver("13800138000"))
# 主题状态变化,通知所有观察者
subject.notify("您的订单已发货!")
# 输出:
# 向 user1@example.com 发送邮件通知:您的订单已发货!
# 向 13800138000 发送短信通知:您的订单已发货!
2. 策略模式:封装可替换的算法
- 核心思想:定义一系列算法,将每个算法封装起来,并且使它们可以相互替换,算法独立于使用它的客户端。
- 生活类比:出行导航,可选择 “最快路线”“最短路线”“避开高速” 等策略,用户按需切换,无需关心路线计算细节。
- 适用场景:支付方式(支付宝 / 微信 / 信用卡)、排序算法、数据验证规则、搜索策略。
- Python 实现(支付策略):
python
运行
# 抽象策略:支付接口
class PaymentStrategy:
def pay(self, amount):
raise NotImplementedError("必须实现支付方法")
# 具体策略1:支付宝支付
class AlipayStrategy(PaymentStrategy):
def pay(self, amount):
return f"通过支付宝支付 {amount} 元,已优惠 5 元"
# 具体策略2:微信支付
class WechatPayStrategy(PaymentStrategy):
def pay(self, amount):
return f"通过微信支付 {amount} 元,赠送积分 10 点"
# 具体策略3:信用卡支付
class CreditCardStrategy(PaymentStrategy):
def pay(self, amount):
return f"通过信用卡支付 {amount} 元,分期免息"
# 上下文:统一支付入口
class PaymentContext:
def __init__(self, strategy):
self.strategy = strategy # 注入具体策略
# 切换策略
def set_strategy(self, strategy):
self.strategy = strategy
# 执行支付
def execute_pay(self, amount):
return self.strategy.pay(amount)
# 使用示例
context = PaymentContext(AlipayStrategy())
print(context.execute_pay(200)) # 输出:通过支付宝支付 200 元,已优惠 5 元
# 切换为微信支付策略
context.set_strategy(WechatPayStrategy())
print(context.execute_pay(200)) # 输出:通过微信支付 200 元,赠送积分 10 点
3. 模板方法模式:固定算法骨架
- 核心思想:定义一个算法的骨架流程,将某些步骤延迟到子类中实现,子类可重写特定步骤,但不改变算法整体结构。
- 生活类比:冲泡饮料的流程(烧水→加原料→冲泡→加调料),泡茶和泡咖啡只需改变 “原料” 和 “调料”,流程保持不变。
- 适用场景:框架设计、重复流程封装(如数据导出、测试用例执行)。
- Python 实现(数据导出模板):
python
运行
# 抽象模板:数据导出骨架
class DataExporter:
def export(self, data):
"""模板方法:固定导出流程"""
self.validate_data(data) # 步骤1:验证数据(固定)
self.process_data(data) # 步骤2:处理数据(子类实现)
self.save_data(data) # 步骤3:保存数据(子类实现)
self.notify_result() # 步骤4:通知结果(固定)
return "导出完成"
def validate_data(self, data):
"""固定步骤:验证数据合法性"""
if not isinstance(data, dict):
raise ValueError("数据必须是字典类型")
print("数据验证通过")
def process_data(self, data):
"""抽象步骤:子类实现数据处理"""
raise NotImplementedError("子类必须实现数据处理方法")
def save_data(self, data):
"""抽象步骤:子类实现数据保存"""
raise NotImplementedError("子类必须实现数据保存方法")
def notify_result(self):
"""固定步骤:通知导出结果"""
print("导出结果已通知管理员")
# 具体模板1:CSV导出
class CsvExporter(DataExporter):
def process_data(self, data):
print("将数据转换为CSV格式")
def save_data(self, data):
print("保存CSV文件到本地")
# 具体模板2:JSON导出
class JsonExporter(DataExporter):
def process_data(self, data):
print("将数据转换为JSON格式")
def save_data(self, data):
print("上传JSON文件到服务器")
# 使用示例
csv_exporter = CsvExporter()
print(csv_exporter.export({"name": "测试数据", "value": 100}))
# 输出:
# 数据验证通过
# 将数据转换为CSV格式
# 保存CSV文件到本地
# 导出结果已通知管理员
# 导出完成
json_exporter = JsonExporter()
print(json_exporter.export({"name": "测试数据", "value": 100}))
# 输出:
# 数据验证通过
# 将数据转换为JSON格式
# 上传JSON文件到服务器
# 导出结果已通知管理员
# 导出完成
四、设计模式核心总结与使用原则
1. 常用模式速查表
| 模式类型 | 模式名称 | 核心作用 | 一句话使用场景 |
|---|---|---|---|
| 创建型 | 单例模式 | 确保唯一实例 | 全局配置、连接池 |
| 创建型 | 工厂方法 | 延迟实例化 | 多类型对象创建(如多数据库连接) |
| 创建型 | 建造者模式 | 分步构建复杂对象 | SQL 构建、复杂配置组装 |
| 结构型 | 适配器模式 | 接口适配 | 整合旧系统、第三方库 |
| 结构型 | 装饰器模式 | 动态添加功能 | 日志、缓存、权限校验 |
| 结构型 | 外观模式 | 简化子系统调用 | 复杂系统封装、接口聚合 |
| 行为型 | 观察者模式 | 一对多通知 | 事件驱动、消息通知 |
| 行为型 | 策略模式 | 算法替换 | 支付方式、排序算法 |
| 行为型 | 模板方法 | 固定算法骨架 | 框架设计、重复流程封装 |
2. 关键使用原则
- 不要为了用模式而用模式:模式是解决问题的工具,而非代码 “炫技” 的手段。
- 优先简化,再用模式:简单问题直接写代码,复杂问题(需扩展、复用)再考虑模式。
- 理解本质,灵活变通:Python 中无需严格遵循设计模式的 “类结构”,可结合语言特性(如装饰器语法、动态类型)简化实现。
设计模式的核心价值是 “解耦” 和 “复用”,掌握这些常用模式后,面对复杂业务场景时能快速给出合理的代码结构设计,让项目更易维护、扩展。建议先从单例、装饰器、观察者这几个高频模式入手,在实际项目中尝试应用,逐步积累经验。