Python 设计模式全解析

设计模式不是刻板的代码模板,而是被反复验证的解决软件共性问题的思路框架——而 Python 的动态类型、高阶函数、元类等特性,刚好能让这些思路落地得比静态语言更“轻量”,甚至“隐形”地融入日常代码中。

本文通过 Python 原生语法或极简代码实现,快速拆解三类核心设计模式,带你避开“为用模式而用模式”的误区。

完整参考实现库(GitHub 万星+): faif/python-patterns


一、 创建型模式 (Creational Patterns)

核心逻辑: 别让调用方直接 new/创建对象——把创建细节封装起来,既解耦系统与具体类,又能灵活控制实例化的方式、时机、数量。

1. 工厂方法 (Factory Method)

不用显式知道具体类名,通过输入参数/配置环境从工厂函数/方法里“拿”对象。

# Python 可以直接用函数当“工厂”,不需要定义单独的工厂类!
def get_serializer(fmt: str):
    """根据格式字符串返回对应的序列化函数"""
    match fmt:
        case "json":
            return lambda data: f"JSON: {data}"
        case "xml":
            return lambda data: f"XML: {data}"
        case _:
            return str  # 默认返回字符串序列化

# 调用方完全不用关心具体序列化类的实现
if __name__ == "__main__":
    serializer = get_serializer("json")
    print(serializer({"name": "Python"}))  # JSON: {'name': 'Python'}
  • ✅ 优点:屏蔽对象创建细节,新增格式(比如 yaml)只需修改工厂函数,不碰调用方代码
  • ❌ 缺点:简单场景下(只有2种可选对象)会增加一点点逻辑成本
  • 📌 适用:需根据配置动态选择实例/工具类的场景

2. 抽象工厂 (Abstract Factory)

工厂的“升级款”——负责生产一整套相关/兼容的产品家族(比如一套皮肤里的按钮、背景、字体),保证它们不会“混搭出错”。

from dataclasses import dataclass

# 先定义“产品族”的组成部分
@dataclass
class Button: text: str; theme: str
@dataclass
class Background: color: str

# 具体产品
class DarkButton(Button): theme = "dark"
class LightButton(Button): theme = "light"
class DarkBackground(Background): color = "#1a1a1a"
class LightBackground(Background): color = "#ffffff"

# 抽象工厂的Python极简实现:用类本身当工厂!
class DarkThemeFactory:
    @staticmethod
    def create_button(text: str) -> Button:
        return DarkButton(text=text, theme="dark")
    @staticmethod
    def create_background() -> Background:
        return DarkBackground()

class LightThemeFactory:
    @staticmethod
    def create_button(text: str) -> Button:
        return LightButton(text=text, theme="light")
    @staticmethod
    def create_background() -> Background:
        return LightBackground()

# 使用:只需选择一次工厂,后续所有组件都是配套的
def setup_ui(factory):
    btn = factory.create_button("开始")
    bg = factory.create_background()
    print(f"按钮: {btn}, 背景: {bg}")

setup_ui(DarkThemeFactory)
  • ✅ 优点:强制产品族统一风格,不会出现“浅色按钮配黑色背景”的低级错误
  • ❌ 缺点:扩展“产品族的维度”(比如新增圆角/直角)很麻烦,要改所有工厂
  • 📌 适用:换肤系统、多数据库(MySQL/PostgreSQL)配套连接+查询工具

3. 单例模式 (Singleton)

保证某个类全局只有一个实例,且提供统一的访问入口。Python 实现方式很多,这里用最简单的 __new__ 魔法方法:

class AppConfig:
    _instance = None  # 私有静态变量存唯一实例
    _data = None      # 存配置数据

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._data = {  # 仅在首次创建时初始化
                "api_key": "123456",
                "timeout": 30
            }
        return cls._instance

# 验证单例
cfg1 = AppConfig()
cfg2 = AppConfig()
print(cfg1 is cfg2)  # True,是同一个对象
  • ✅ 优点:节约内存(比如数据库连接池、全局日志管理器),避免重复初始化
  • ❌ 缺点:违背单一职责原则(既管自身创建,又管业务数据),多线程环境下要加锁
  • 📌 适用:配置管理、日志系统、全局唯一资源管理器

二、 结构型模式 (Structural Patterns)

核心逻辑: 怎么把类/对象灵活组合起来实现更大的功能,而不是用“继承树”堆得无法维护。

4. 装饰器模式 (Decorator)

Python 自带语法糖 @decorator 完美适配这个模式!动态地给对象/函数“加功能”,不修改其源代码

# 定义装饰器(用函数当装饰器)
def bold(func):
    """给返回值加加粗标签"""
    def wrapper(*args, **kwargs):
        return f"<b>{func(*args, **kwargs)}</b>"
    return wrapper

def italic(func):
    """给返回值加斜体标签"""
    def wrapper(*args, **kwargs):
        return f"<i>{func(*args, **kwargs)}</i>"
    return wrapper

# 叠加装饰器!顺序很重要:先执行下面的,再执行上面的
@bold
@italic
def say_hello(name: str) -> str:
    return f"Hello, {name}!"

# 测试
print(say_hello("Python"))  # <b><i>Hello, Python!</i></b>
  • ✅ 优点:比继承灵活(可以叠加任意多个装饰器,顺序可调),完全符合开闭原则
  • ❌ 缺点:多个嵌套装饰器会让调试变难(比如报错堆栈可能指向 wrapper)
  • 📌 适用:日志记录、性能监控、权限校验、缓存

5. 代理模式 (Proxy)

给目标对象加一个“替身”,调用方先访问替身,替身可以控制访问权限、延迟加载目标、缓存结果

# 目标对象:加载图片很耗时
class RealImage:
    def __init__(self, filename: str):
        self.filename = filename
        self._load_from_disk()  # 初始化时就加载

    def _load_from_disk(self):
        print(f"正在从磁盘加载图片:{self.filename}")

    def display(self):
        print(f"正在显示图片:{self.filename}")

# 代理对象:延迟加载,只有第一次 display 才加载
class ProxyImage:
    def __init__(self, filename: str):
        self.filename = filename
        self._real_image = None  # 初始不加载

    def display(self):
        if self._real_image is None:
            self._real_image = RealImage(self.filename)
        self._real_image.display()

# 测试
img = ProxyImage("cat.jpg")  # 这里没输出加载信息
print("准备显示图片...")
img.display()  # 第一次显示才加载
img.display()  # 第二次直接显示,不用再加载
  • ✅ 优点:控制访问、延迟加载、缓存结果、隐藏真实对象的实现
  • ❌ 缺点:增加了一层中间层,调用速度会有极微小的损耗
  • 📌 适用:图片懒加载、远程服务代理、安全控制(检查用户权限后再调用真实对象)

三、 行为型模式 (Behavioral Patterns)

核心逻辑: 关注对象之间怎么通信、怎么分工,让交互更清晰、更易扩展。

6. 迭代器模式 (Iterator)

Python 原生支持!不用手动定义复杂的迭代器类(除非要自定义遍历逻辑)——只要实现 __iter____next__ 魔法方法,或者直接用内置的 iter()next()

# 1. 内置集合(列表、字典、字符串)都是可迭代的
for num in [1, 2, 3]:
    print(num)

# 2. 自定义一个简单的迭代器:遍历斐波那契数列的前N项
class FibonacciIterator:
    def __init__(self, n: int):
        self.n = n  # 前N项
        self.a, self.b = 0, 1  # 初始两项
        self.count = 0  # 已遍历的数量

    def __iter__(self):
        return self  # 迭代器本身要返回自己

    def __next__(self):
        if self.count >= self.n:
            raise StopIteration  # 遍历结束抛出异常
        self.count += 1
        self.a, self.b = self.b, self.a + self.b
        return self.a

# 测试自定义迭代器
for fib in FibonacciIterator(5):
    print(fib)  # 1 1 2 3 5
  • ✅ 优点:访问集合内容而不暴露内部结构,支持多种遍历方式(比如正向/反向遍历树)
  • ❌ 缺点:对于简单的列表、字典,手动实现迭代器有点多余
  • 📌 适用:遍历数据库查询结果、处理大型流式文件、自定义数据结构

本文只覆盖了最常用的6种设计模式,剩下的可以结合开头的参考代码库深入学习。记住:模式是工具,不是目的——当你遇到问题时,先想“有没有现成的模式能解决”,再决定要不要用,怎么用最 Pythonic。