Python设计模式综合实践
GoF设计模式的Pythonic实现
一、引言:设计模式与Python哲学
设计模式(Design Patterns)源自GoF(Gang of Four)的经典著作《Design Patterns: Elements of Reusable Object-Oriented Software》。这23种模式并非凭空创造的规则,而是对反复出现的软件设计问题的成熟解决方案的总结。然而,GoF模式最初基于C++和Smalltalk等静态类型语言的实践,在Python这样的动态语言中,许多模式的实现可以大幅简化,甚至完全内化为语言特性。
Python之禅(Zen of Python)中的核心理念 —— "Simple is better than complex" 和 "There should be one -- and preferably only one -- obvious way to do it" —— 应该成为我们在Python中应用设计模式的指导原则。不要为了用模式而用模式,当Python语言自身已提供了更简洁的解决方案时,应优先使用Pythonic的方式。
核心观点:
设计模式是解决方案的命名与归纳 ,而非创造新规则
Python的动态特性(一等函数、元类、描述符协议、上下文管理器)可大幅简化模式实现
不要为了模式而模式,Pythonic优先于"纯正"的GoF实现
理解模式的本质比记忆UML图更重要
二、创建型模式的Python简化
创建型模式关注对象创建机制,试图以灵活的方式创建对象,隐藏创建逻辑。在Python中,由于语言本身支持关键字参数、类方法、模块单例等特性,创建型模式的实现变得异常简洁。
2.1 单例模式(Singleton)
单例模式确保一个类只有一个实例,并提供全局访问点。在静态语言中通常需要私有构造函数和静态方法,但Python提供了多种更简洁的方式。
方式一:模块单例(最Pythonic)
Python模块天然是单例的,导入一次后即被缓存。这是最推荐的方式。
# singleton_module.py -- 模块级单例,最Pythonic的方式
# Python模块在首次导入后即被sys.modules缓存,后续导入返回同一对象
class DatabaseConnection :
def __init__ (self , host, port):
self .host = host
self .port = port
self ._connected = False
def connect (self ):
self ._connected = True
return f"Connected to {self.host}:{self.port}"
# 在模块作用域直接实例化,全局唯一
db = DatabaseConnection("localhost" , 5432 )
方式二:使用装饰器
利用装饰器封装单例逻辑,对任何类即插即用。
from functools import wraps
def singleton (cls):
"""单例装饰器:确保类只有一个实例"""
instances = {}
@wraps (cls)
def get_instance (*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class AppConfig :
def __init__ (self ):
self .settings = {}
# 验证单例
a = AppConfig()
b = AppConfig()
assert a is b # True
# 方式三:使用元类(适合框架级实现)
class SingletonMeta (type ):
_instances = {}
def __call__ (cls , *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super ().__call__(*args, **kwargs)
return cls._instances[cls]
class Logger (metaclass =SingletonMeta):
def __init__ (self ):
self .logs = []
def log (self , msg):
self .logs.append(msg)
Pythonic建议
模块单例是首选方案,因为它利用了语言内置机制,无需额外代码。装饰器方式适合需要对多个类复用单例逻辑的场景。元类方式最重量级,仅在框架或库开发中需要干预类创建过程时使用。
2.2 工厂模式(Factory)
工厂模式将对象创建逻辑封装起来,客户端无需知道具体类名。Python的动态类型和关键字参数使得工厂模式异常简洁。
# 简单工厂 -- 用函数即可,无需工厂类
from enum import Enum, auto
class AnimalType (Enum):
DOG = auto()
CAT = auto()
DUCK = auto()
class Dog :
def speak (self ): return "Woof!"
class Cat :
def speak (self ): return "Meow!"
class Duck :
def speak (self ): return "Quack!"
def create_animal (animal_type: AnimalType):
"""简单工厂函数 -- 在Python中函数就是一等的工厂"""
mapping = {
AnimalType.DOG: Dog,
AnimalType.CAT: Cat,
AnimalType.DUCK: Duck,
}
return mapping[animal_type]()
# 使用 -- 客户端无需知道具体类
animal = create_animal(AnimalType.DOG)
print (animal.speak()) # Woof!
工厂方法 vs 抽象工厂
在GoF中,工厂方法通过子类重写来创建不同产品,抽象工厂用于创建产品族。Python中利用类方法和模块级函数可以大幅简化这两者。
# 工厂方法 -- 使用类方法,Python原生支持
class Serializer :
@classmethod
def create (cls , fmt: str ):
"""类方法作为工厂方法"""
subclasses = {sub.__name__.lower(): sub for sub in cls.__subclasses__()}
return subclasses.get(fmt, cls)()
def serialize (self , data): return str (data)
class JsonSerializer (Serializer):
def serialize (self , data):
import json
return json.dumps(data)
class XmlSerializer (Serializer):
def serialize (self , data):
# XML序列化实现...
return f"<data>{data}</data>"
# 使用 -- 自动发现子类
serializer = Serializer.create("jsonserializer" )
print (serializer.serialize({"key" : "value" }))
# 抽象工厂 -- 使用字典作为注册表,比类层次更灵活
class GUIFactory :
"""使用注册表的抽象工厂 -- Pythonic方式"""
_factories = {}
@classmethod
def register (cls , name):
"""装饰器注册工厂"""
def wrapper (factory_cls):
cls._factories[name] = factory_cls
return factory_cls
return wrapper
@classmethod
def create (cls , name, theme):
factory = cls._factories.get(name)
if not factory:
raise ValueError (f"Unknown factory: {name}" )
return factory(theme)
@GUIFactory.register("windows")
class WindowsFactory :
def __init__ (self , theme):
self .theme = theme
def create_button (self ): return f"Windows [{self.theme}] Button"
def create_menu (self ): return f"Windows [{self.theme}] Menu"
@GUIFactory.register("mac")
class MacFactory :
def __init__ (self , theme):
self .theme = theme
def create_button (self ): return f"macOS [{self.theme}] Button"
def create_menu (self ): return f"macOS [{self.theme}] Menu"
# 使用
factory = GUIFactory.create("windows" , "dark" )
print (factory.create_button()) # Windows [dark] Button
2.3 建造者模式(Builder)
建造者模式用于构建复杂对象,分离构建过程与表示。Python的特性使得这一模式可以大幅简化:命名参数、链式调用、dataclass等。
# Pythonic建造者 -- 链式调用 + dataclass
from dataclasses import dataclass, field
@dataclass
class Computer :
"""最终产品 -- dataclass自动生成__init__和__repr__"""
cpu: str = "Standard CPU"
ram_gb: int = 8
storage_gb: int = 256
gpu: str = "Integrated"
os: str = "Linux"
has_wifi: bool = True
extras: list = field(default_factory=list )
class ComputerBuilder :
"""建造者 -- 通过链式调用提供流畅的构建体验"""
def __init__ (self ):
self .computer = Computer()
def cpu (self , model: str ):
self .computer.cpu = model; return self
def ram (self , gb: int ):
self .computer.ram_gb = gb; return self
def storage (self , gb: int ):
self .computer.storage_gb = gb; return self
def gpu (self , model: str ):
self .computer.gpu = model; return self
def os (self , name: str ):
self .computer.os = name; return self
def add_extra (self , item: str ):
self .computer.extras.append(item); return self
def build (self ) -> Computer:
return self .computer
# 使用 -- 流畅的链式接口
gaming_pc = (ComputerBuilder()
.cpu("Intel i9-13900K" )
.ram(64 )
.storage(2000 )
.gpu("NVIDIA RTX 4090" )
.os("Windows 11" )
.add_extra("RGB Lighting" )
.build())
print (gaming_pc)
Pythonic简化
在许多场景下,直接使用命名参数 和dataclass 就足以替代完整的建造者模式。建造者模式的真正价值在于当构建过程涉及多个步骤、参数之间有复杂的依赖关系,或需要创建不同的产品变体时。
2.4 原型模式(Prototype)
原型模式通过复制已有对象来创建新对象,避免重复的初始化开销。Python的copy模块提供了原生支持。
# 原型模式 -- Python的copy模块原生支持
import copy
from dataclasses import dataclass, field
@dataclass
class WebPage :
title: str
content: str
styles: list = field(default_factory=list )
scripts: list = field(default_factory=list )
meta_tags: dict = field(default_factory=dict )
def clone (self , **updates):
"""克隆并应用更新 -- 结合原型+建造者思路"""
new = copy.deepcopy(self )
for key, value in updates.items():
setattr (new, key, value)
return new
# 创建原型实例
base_page = WebPage(
title="Base" ,
content="Default content" ,
styles=["bootstrap.css" , "main.css" ],
scripts=["jquery.js" , "app.js" ],
meta_tags={"charset" : "utf-8" , "viewport" : "responsive" }
)
# 通过原型克隆创建不同页面 -- 无需重新初始化
home_page = base_page.clone(title="Home" , content="Welcome!" )
about_page = base_page.clone(title="About Us" , content="Our story" )
contact_page = base_page.clone(title="Contact" , content="Get in touch" ,
scripts=["jquery.js" , "app.js" , "map.js" ])
print (home_page.title) # Home
print (about_page.styles) # ['bootstrap.css', 'main.css'] -- 共享样式
创建型模式总结
Python模块本身就是单例,无需额外实现
一等函数和字典注册表使工厂模式比类继承更灵活
dataclass + 链式调用简化建造者模式
copy模块原生支持原型模式
三、结构型模式的动态特性优化
结构型模式关注类和对象的组合,通过继承或组合构建更大的结构。Python的动态特性(鸭子类型、__getattr__、装饰器)让结构型模式更加灵活简洁。
3.1 适配器模式(Adapter)
适配器模式让接口不兼容的类能够协作。Python的鸭子类型特性使得适配器实现异常简洁 —— 只要对象有正确的方法,就能被使用。
# 类适配器 -- 通过继承 + 组合实现
class USBDevice :
"""客户端期望的接口"""
def connect_via_usb (self ):
pass
def transfer_data (self , data):
pass
class HDMICable :
"""需要适配的类 -- 接口不兼容"""
def plug_hdmi (self ):
return "HDMI plugged"
def send_signal (self , signal):
return f"Sending signal: {signal} via HDMI"
class HDMItoUSBAdapter (USBDevice):
"""适配器:将HDMI接口适配为USB接口"""
def __init__ (self , hdmi_device: HDMICable):
self ._hdmi = hdmi_device
def connect_via_usb (self ):
return self ._hdmi.plug_hdmi()
def transfer_data (self , data):
return self ._hdmi.send_signal(data)
# Pythonic方式:直接包装(鸭子类型 -- 不需要显式继承USBDevice)
def use_usb_device (device):
"""任何拥有connect_via_usb和transfer_data方法的对象都可以使用"""
device.connect_via_usb()
return device.transfer_data("hello" )
# 匿名适配器 -- 函数式适配,最Pythonic
hdmi = HDMICable()
adapter = type ('AnonymousAdapter' , (), {
'connect_via_usb' : hdmi.plug_hdmi,
'transfer_data' : lambda data: hdmi.send_signal(data),
})
print (use_usb_device(adapter))
3.2 装饰器模式(Decorator)
装饰器模式动态地给对象添加额外职责。在Python中,这个模式已经上升为语言特性 —— 函数装饰器和类装饰器。这是GoF模式与Python语言完美融合的最佳例子。
# Python装饰器 = 语言内置的装饰器模式
from functools import wraps
import time
def log_execution_time (func):
"""函数装饰器:记录函数执行时间 -- GoF装饰器模式的Pythonic实现"""
@wraps (func)
def wrapper (*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print (f"[TIMING] {func.__name__} took {elapsed:.4f}s" )
return result
return wrapper
def retry (max_attempts=3 , delay=0.1 ):
"""带参数的装饰器:重试逻辑"""
def decorator (func):
@wraps (func)
def wrapper (*args, **kwargs):
for attempt in range (1 , max_attempts + 1 ):
try :
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts:
raise
print (f"[RETRY] Attempt {attempt} failed: {e}" )
time.sleep(delay)
return None
return wrapper
return decorator
@log_execution_time
@retry(max_attempts=2)
def unreliable_api_call (url):
"""装饰器可以叠加使用 -- 多个职责组合"""
if time.time() % 2 < 0.5 :
raise ConnectionError("Network timeout" )
return f"Data from {url}"
# 类装饰器 -- 应用于整个类的装饰器
def add_str_repr (cls):
"""类装饰器:为类添加__str__和__repr__方法"""
def __str__ (self ):
items = sorted (vars (self ).items())
return f"{cls.__name__}({', '.join(f'{k}={v}' for k, v in items)})"
cls.__str__ = __str__
cls.__repr__ = __str__
cls.__name__ = cls.__name__
return cls
@add_str_repr
class Book :
def __init__ (self , title, author, year):
self .title = title
self .author = author
self .year = year
print (Book("Python Cookbook" , "David Beazley" , 2013 ))
# Book(title=Python Cookbook, author=David Beazley, year=2013)
3.3 外观模式(Facade)
外观模式为复杂子系统提供统一的高层接口。这是Python中极其常用的模式(尤其在库设计中)。
# 外观模式 -- 为复杂系统提供简洁接口
class VideoFile :
def __init__ (self , path):
self .path = path
self .codec = self ._detect_codec()
def _detect_codec (self ):
return "h264" if self .path.endswith(".mp4" ) else "hevc"
class AudioExtractor :
def extract (self , file): return f"audio from {file.path}"
class SubtitleParser :
def parse (self , file): return f"subtitles from {file.path}"
class Transcoder :
def transcode (self , file, target): return f"transcoded to {target}"
class VideoConverter :
"""外观 -- 为视频转换提供统一接口"""
def __init__ (self ):
self ._audio_extractor = AudioExtractor()
self ._subtitle_parser = SubtitleParser()
self ._transcoder = Transcoder()
def convert (self , source_path, target_format):
"""统一接口:客户端只需调用这一个方法"""
file = VideoFile(source_path)
audio = self ._audio_extractor.extract(file)
subs = self ._subtitle_parser.parse(file)
result = self ._transcoder.transcode(file, target_format)
return {
"source" : source_path,
"format" : target_format,
"audio" : audio,
"subtitles" : subs,
"result" : result,
}
# 客户端只需知道外观接口
converter = VideoConverter()
result = converter.convert("movie.mp4" , "avi" )
print (result["result" ]) # transcoded to avi
3.4 代理模式(Proxy)
代理模式为其他对象提供代理以控制对该对象的访问。Python的__getattr__和描述符协议让代理实现更加优雅。
# 代理模式 -- 利用__getattr__自动转发
class LazyImage :
"""虚拟代理 -- 延迟加载大图"""
def __init__ (self , path):
self .path = path
self ._real_image = None
def _load_image (self ):
print (f"[LOAD] Loading image from {self.path}" )
self ._real_image = RealImage(self .path)
def display (self ):
"""首次调用时加载,后续复用"""
if not self ._real_image:
self ._load_image()
return self ._real_image.display()
class RealImage :
def __init__ (self , path):
self .path = path
def display (self ):
return f"Displaying image: {self.path}"
# 保护代理 -- 使用描述符实现访问控制
class AccessControl :
"""描述符:实现属性级别的访问控制"""
def __init__ (self , permission):
self .permission = permission
self ._value = None
def __get__ (self , obj, objtype=None ):
if not obj or not getattr (obj, '_user' , None ):
raise PermissionError("No user set" )
if not hasattr (obj._user, self .permission):
raise PermissionError(f"Need {self.permission} permission" )
return self ._value
def __set__ (self , obj, value):
self ._value = value
3.5 组合模式(Composite)
组合模式将对象组合成树形结构以表示"部分-整体"的层次结构。Python的鸭子类型和协议让组合模式实现非常自然。
# 组合模式 -- 统一的迭代接口
from abc import ABC, abstractmethod
class FileSystemNode (ABC):
"""抽象组件"""
@abstractmethod
def get_size (self ) -> int :
pass
@abstractmethod
def list (self , indent="" ) -> str :
pass
class File (FileSystemNode):
"""叶子节点"""
def __init__ (self , name, size):
self .name = name
self ._size = size
def get_size (self ):
return self ._size
def list (self , indent="" ):
return f"{indent}📄 {self.name} ({self._size} bytes)"
class Directory (FileSystemNode):
"""复合节点 -- 可以包含叶子和其他复合节点"""
def __init__ (self , name):
self .name = name
self ._children = []
def add (self , node: FileSystemNode):
self ._children.append(node)
return self # 链式调用
def remove (self , node: FileSystemNode):
self ._children.remove(node)
def get_size (self ):
return sum (child.get_size() for child in self ._children)
def list (self , indent="" ):
lines = [f"{indent}📁 {self.name}/ ({self.get_size()} bytes)" ]
for child in self ._children:
lines.append(child.list(indent + " " ))
return "\n" .join(lines)
# 构建文件系统树
root = Directory("project" )
src = Directory("src" )
root.add(src)
src.add(File("main.py" , 1024 )).add(File("utils.py" , 512 ))
root.add(File("README.md" , 256 ))
print (root.list())
# 📁 project/ (1792 bytes)
# 📁 src/ (1536 bytes)
# 📄 main.py (1024 bytes)
# 📄 utils.py (512 bytes)
# 📄 README.md (256 bytes)
print (f"Total size: {root.get_size()} bytes" ) # 1792
3.6 桥接模式(Bridge)
桥接模式将抽象部分与实现部分分离。Python的鸭子类型使得桥接异常简洁。
# 桥接模式 -- 抽象与实现分离
# 实现层次:不同渲染引擎
class VectorRenderer :
def render_circle (self , radius):
return f"Vector: Drawing circle with radius {radius}"
def render_square (self , side):
return f"Vector: Drawing square with side {side}"
class RasterRenderer :
def render_circle (self , radius):
return f"Raster: Drawing circle as pixels, radius={radius}"
def render_square (self , side):
return f"Raster: Drawing square as pixels, side={side}"
# 抽象层次:不同形状
class Shape :
"""桥接抽象 -- 持有渲染器的引用"""
def __init__ (self , renderer):
self .renderer = renderer
def draw (self ): pass
def resize (self , factor): pass
class Circle (Shape):
def __init__ (self , renderer, radius):
super ().__init__(renderer)
self .radius = radius
def draw (self ):
return self .renderer.render_circle(self .radius)
def resize (self , factor):
self .radius *= factor
# 使用 -- 自由组合抽象和实现
vector_circle = Circle(VectorRenderer(), 5 )
raster_circle = Circle(RasterRenderer(), 10 )
print (vector_circle.draw()) # Vector: Drawing circle with radius 5
print (raster_circle.draw()) # Raster: Drawing circle as pixels...
3.7 享元模式(Flyweight)
享元模式通过共享大量细粒度对象来节省内存。Python的functools.lru_cache和共享引用让享元实现非常直接。
# 享元模式 -- 使用缓存共享对象
from functools import lru_cache
class CharacterStyle :
"""享元对象 -- 内部状态(可共享)"""
def __init__ (self , font, size, bold, italic, color):
self .font = font
self .size = size
self .bold = bold
self .italic = italic
self .color = color
def __repr__ (self ):
return f"Style({self.font}, {self.size}, bold={self.bold})"
class StyleFactory :
"""享元工厂 -- 缓存和复用样式对象"""
_cache = {}
@classmethod
def get_style (cls , font, size, bold, italic, color):
key = (font, size, bold, italic, color)
if key not in cls._cache:
cls._cache[key] = CharacterStyle(font, size, bold, italic, color)
return cls._cache[key]
# 使用functools.lru_cache作为享元
@lru_cache(maxsize=128)
def get_style_flyweight (font, size, bold, italic, color):
"""函数级享元 -- 更Pythonic的方式"""
return CharacterStyle(font, size, bold, italic, color)
# 验证共享
s1 = get_style_flyweight("Arial" , 12 , False , False , "black" )
s2 = get_style_flyweight("Arial" , 12 , False , False , "black" )
print (s1 is s2) # True -- 同一个对象
print (get_style_flyweight.cache_info()) # CacheInfo(hits=0, misses=1, ...)
结构型模式总结
Python的鸭子类型使适配器模式几乎"隐形"
函数装饰器和类装饰器是装饰器模式的终极Pythonic实现
__getattr__和描述符协议让代理模式实现更加简洁
lru_cache天然适合享元模式的缓存共享需求
四、行为型模式的函数式简化
行为型模式关注对象之间的通信和责任分配。Python的一等函数、闭包、生成器等特性,使得许多行为型模式可以用函数式的方式大幅简化。
4.1 策略模式(Strategy)
策略模式定义一系列算法并使其可互换。在Python中,策略就是一等函数 —— 不需要策略类层次结构。
# 策略模式 -- 一等函数即策略
from decimal import Decimal, ROUND_HALF_UP
from dataclasses import dataclass
from typing import Callable
# 策略就是普通函数,不需要类
def percentage_discount (price: Decimal, total: Decimal) -> Decimal:
"""满100打9折"""
return total * Decimal("0.9" ) if total >= Decimal("100" ) else total
def fixed_amount_discount (price: Decimal, total: Decimal) -> Decimal:
"""满200减30"""
return total - Decimal("30" ) if total >= Decimal("200" ) else total
def loyalty_discount (price: Decimal, total: Decimal) -> Decimal:
"""会员95折"""
return total * Decimal("0.95" ) if True else total
def no_discount (price: Decimal, total: Decimal) -> Decimal:
return total
@dataclass
class Order :
items: list
prices: list
discount_strategy: Callable = no_discount
def calculate_total (self ) -> Decimal:
total = sum (self .prices, Decimal("0" ))
return self .discount_strategy(self .prices[0 ], total)
# 运行时更换策略
order = Order(
items=["Book" , "Pen" ],
prices=[Decimal("80" ), Decimal("30" )],
discount_strategy=percentage_discount
)
print (f"Total after discount: {order.calculate_total()}" ) # 99.0
# 甚至可以用lambda作为即用策略
order.discount_strategy = lambda p, t: t * Decimal("0.8" )
print (f"Total after special: {order.calculate_total()}" ) # 88.0
4.2 观察者模式(Observer)
观察者模式定义一对多依赖,当一个对象状态改变时自动通知依赖对象。Python的事件系统、回调函数和弱引用让观察者模式实现非常简洁。
# 观察者模式 -- 基于回调函数的Pythonic实现
from typing import Callable, list
from weakref import ref
class Observable :
"""基于回调的事件源 -- 比标准观察者模式更Pythonic"""
def __init__ (self ):
self ._observers = [] # 存储回调函数
def register (self , callback: Callable):
"""注册观察者(回调)"""
self ._observers.append(callback)
return callback # 支持装饰器用法
def unregister (self , callback):
self ._observers.remove(callback)
def _notify (self , event, **data):
"""通知所有观察者"""
for callback in list (self ._observers):
callback(event, self , **data)
class WeatherStation (Observable):
def __init__ (self ):
super ().__init__()
self ._temperature = 0
self ._humidity = 0
@property
def temperature (self ):
return self ._temperature
@temperature.setter
def temperature (self , value):
self ._temperature = value
self ._notify("temperature_changed" , new_value=value)
@property
def humidity (self ):
return self ._humidity
@humidity.setter
def humidity (self , value):
self ._humidity = value
self ._notify("humidity_changed" , new_value=value)
# 观察者就是普通函数
def log_temperature (event, source, **data):
print (f"[LOG] Temperature changed to {data['new_value']}C" )
@station.register # 装饰器注册
def alert_if_hot (event, source, **data):
if event == "temperature_changed" and data["new_value" ] > 35 :
print ("[ALERT] High temperature warning!" )
station = WeatherStation()
station.register(log_temperature) # 普通注册
station.temperature = 30 # [LOG] Temperature changed to 30C
station.temperature = 36 # [LOG] + [ALERT]
4.3 命令模式(Command)
命令模式将请求封装为对象。Python中函数本身就是对象,可以作为命令传递,函数装饰器也可以实现更复杂的命令包装。
# 命令模式 -- 函数即命令
from dataclasses import dataclass
from typing import Callable
import datetime
@dataclass
class Command :
"""命令对象 -- 封装可调用和元数据"""
action: Callable
args: tuple = ()
kwargs: dict = None
created_at: str = None
def __post_init__ (self ):
self .created_at = datetime.datetime.now().isoformat()
def execute (self ):
return self .action(*self .args, **(self .kwargs or {}))
def __repr__ (self ):
return f"Command({self.action.__name__}, created={self.created_at})"
# 命令队列 -- 支持撤销的命令
class CommandHistory :
def __init__ (self ):
self ._undo_stack = []
self ._redo_stack = []
def execute (self , command: Command):
result = command.execute()
self ._undo_stack.append(command)
self ._redo_stack.clear()
return result
def undo (self ):
if not self ._undo_stack:
return
cmd = self ._undo_stack.pop()
self ._redo_stack.append(cmd)
return f"Undone: {cmd}"
# 具体命令就是普通函数
def add (a, b): return a + b
def multiply (a, b): return a * b
def greet (name): return f"Hello, {name}!"
# 使用
history = CommandHistory()
result = history.execute(Command(add, args=(3 , 4 )))
print (result) # 7
result = history.execute(Command(greet, kwargs={"name" : "Python" }))
print (result) # Hello, Python!
4.4 模板方法模式(Template Method)
模板方法在父类中定义算法骨架,子类覆盖特定步骤。Python中可以用继承,但更灵活的方式是使用高阶函数或依赖注入。
# 模板方法 -- 传统方式 vs Pythonic方式
# 传统方式(GoF风格) -- 使用抽象基类
from abc import ABC, abstractmethod
class DataProcessor (ABC):
"""模板方法模式 -- 骨架由父类定义"""
def process (self ):
"""模板方法 -- 定义算法骨架"""
data = self ._load_data()
cleaned = self ._clean(data)
result = self ._analyze(cleaned)
self ._output(result)
return result
@abstractmethod
def _load_data (self ): pass
def _clean (self , data): return data # 钩子方法
@abstractmethod
def _analyze (self , data): pass
def _output (self , result): print (result)
class CSVProcessor (DataProcessor):
def _load_data (self ): return "csv data"
def _analyze (self , data): return f"analysis of {data}"
# Pythonic方式 -- 使用高阶函数,无需继承
def create_processor (load_fn, analyze_fn, clean_fn=None , output_fn=print ):
"""高阶函数:接受策略函数,返回处理器"""
def process ():
data = load_fn()
cleaned = clean_fn(data) if clean_fn else data
result = analyze_fn(cleaned)
output_fn(result)
return result
return process
# 使用函数式模板方法
processor = create_processor(
load_fn=lambda : "json data" ,
analyze_fn=lambda d: f"analysis of {d}" ,
clean_fn=lambda d: d.strip()
)
result = processor()
4.5 迭代器模式(Iterator)
迭代器模式提供顺序访问聚合对象元素的方法。Python的迭代器协议(__iter__和__next__)和生成器让这一模式完全内化。
# 迭代器模式 -- Python生成器 = 终极迭代器实现
# 方式一:实现迭代器协议
class Range :
def __init__ (self , start, end):
self .start = start
self .end = end
def __iter__ (self ):
return self
def __next__ (self ):
if self .start >= self .end:
raise StopIteration
current = self .start
self .start += 1
return current
# 方式二:生成器函数(最Pythonic)
def fibonacci (limit):
"""生成器函数 -- 即迭代器"""
a, b = 0 , 1
for _ in range (limit):
yield a
a, b = b, a + b
# 方式三:生成器表达式
squares = (x * x for x in range (10 ))
# 方式四:使用itertools组合迭代器
import itertools
# 无限迭代器 + 切片
natural_numbers = itertools.count(1 )
first_ten = itertools.islice(natural_numbers, 10 )
print (list (first_ten)) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 自定义迭代器 -- 遍历树形结构
def walk_tree (node):
"""递归生成器:深度优先遍历树"""
yield node
for child in getattr (node, 'children' , []):
yield from walk_tree(child)
4.6 状态模式(State)
状态模式允许对象在其内部状态改变时改变其行为。Python的枚举和字典派发表可以简化状态机实现。
# 状态模式 -- 使用枚举和函数派发表
from enum import Enum, auto
class TrafficLightState (Enum):
RED = auto()
GREEN = auto()
YELLOW = auto()
class TrafficLight :
"""基于函数派发表的状态机 -- 比GoF状态模式更简洁"""
def __init__ (self ):
self .state = TrafficLightState.RED
# 状态转换表
self ._transitions = {
TrafficLightState.RED: TrafficLightState.GREEN,
TrafficLightState.GREEN: TrafficLightState.YELLOW,
TrafficLightState.YELLOW: TrafficLightState.RED,
}
def change (self ):
self .state = self ._transitions[self .state]
def action (self ):
"""基于当前状态派发行为"""
actions = {
TrafficLightState.RED: lambda : "Stop" ,
TrafficLightState.GREEN: lambda : "Go" ,
TrafficLightState.YELLOW: lambda : "Caution" ,
}
return actions[self .state]()
# 更复杂的状态机 -- 使用状态类
class OrderState :
def next_state (self ): pass
def can_cancel (self ): return False
class PendingState (OrderState):
def next_state (self ): return PaidState()
def can_cancel (self ): return True
class PaidState (OrderState):
def next_state (self ): return ShippedState()
def can_cancel (self ): return False
class ShippedState (OrderState):
def next_state (self ): return DeliveredState()
def can_cancel (self ): return True
class DeliveredState (OrderState):
def next_state (self ): return self
class Order :
def __init__ (self ):
self .state = PendingState()
def advance (self ):
self .state = self .state.next_state()
def can_cancel (self ):
return self .state.can_cancel()
4.7 职责链模式(Chain of Responsibility)
职责链将请求沿处理者链传递。Python中可以用列表或生成器实现优雅的职责链。
# 职责链 -- 函数列表 + 生成器
from typing import Callable, Optional
class LoggingHandler :
"""基于类方法的职责链"""
def __init__ (self ):
self ._handlers = []
def add (self , handler: Callable):
self ._handlers.append(handler)
return self
def handle (self , level, message):
"""沿职责链传递,直到被处理"""
for handler in self ._handlers:
result = handler(level, message)
if result is not None : # 非None表示已处理
return result
return "Unhandled"
# 定义处理器函数
def error_handler (level, msg):
if level == "ERROR" :
return f"[ERROR] {msg}"
return None # 不处理,传递给下一个
def warning_handler (level, msg):
if level == "WARNING" :
return f"[WARNING] {msg}"
return None
def info_handler (level, msg):
if level == "INFO" :
return f"[INFO] {msg}"
return None
# 组装职责链
chain = (LoggingHandler()
.add(error_handler)
.add(warning_handler)
.add(info_handler))
print (chain.handle("ERROR" , "Disk full" )) # [ERROR] Disk full
print (chain.handle("INFO" , "User logged in" )) # [INFO] User logged in
其余行为型模式(中介者、备忘录、访问者、解释器)在日常Python开发中使用频率相对较低,但在特定场景下仍有价值。例如,中介者模式 可以通过事件总线统一协调组件通信,备忘录模式 可以通过__getstate__/__setstate__或pickle实现状态快照,访问者模式 可以通过functools.singledispatch实现泛型函数分发。
行为型模式总结
一等函数让策略、命令、观察者模式"消失"为函数调用
生成器和迭代器协议完全替代了GoF的迭代器模式
枚举+派发表简化了状态模式的实现
函数列表和生成器组成了优雅的职责链
模板方法既可以用继承,也可以用高阶函数注入
五、Python特有设计模式
Python语言本身的特性催生了一些独特的"模式",它们并非GoF的一部分,但在Python生态中广泛使用,是Pythonic代码的核心组成部分。
5.1 可调用对象(Callable Objects)
通过实现__call__,让对象像函数一样调用。这是保存状态的可调用对象(类似闭包)。
# 可调用对象 -- 有状态的函数
class Counter :
"""保存调用次数的可调用对象"""
def __init__ (self ):
self .count = 0
def __call__ (self , *args, **kwargs):
self .count += 1
return f"Called {self.count} times with {args} {kwargs}"
counter = Counter()
print (counter("hello" )) # Called 1 times with ('hello',) {}
print (counter()) # Called 2 times with () {}
print (callable(counter)) # True
# 偏函数 -- functools.partial
from functools import partial
def power (base, exp):
return base ** exp
square = partial(power, exp=2 )
cube = partial(power, exp=3 )
print (square(5 )) # 25
print (cube(3 )) # 27
5.2 上下文管理器(Context Manager)
上下文管理器通过__enter__和__exit__协议实现资源的自动管理。这是Python最著名的特有模式之一。
# 上下文管理器 -- 资源管理的标准模式
class ManagedFile :
"""自定义上下文管理器"""
def __init__ (self , path, mode='r' ):
self .path = path
self .mode = mode
def __enter__ (self ):
self .file = open (self .path, self .mode)
return self .file
def __exit__ (self , exc_type, exc_val, exc_tb):
self .file.close()
return False # 不抑制异常
# 使用contextlib简化
from contextlib import contextmanager
@contextmanager
def timer (name="block" ):
"""用生成器实现的上下文管理器 -- 自动计时"""
import time
start = time.perf_counter()
try :
yield
finally :
elapsed = time.perf_counter() - start
print (f"[{name}] took {elapsed:.4f}s" )
# 嵌套上下文管理器
with timer("database query" ):
with ManagedFile("data.txt" , "r" ) as f:
data = f.read()
5.3 描述符(Descriptor)
描述符通过__get__、__set__、__delete__协议,控制属性访问行为。property、classmethod、staticmethod都是描述符的应用。
# 描述符 -- 控制属性访问
class PositiveNumber :
"""描述符:验证属性为正数"""
def __init__ (self , default=0 ):
self .default = default
def __set_name__ (self , owner, name):
self ._private_name = f"_{name}"
def __get__ (self , obj, objtype=None ):
if obj is None :
return self
return getattr (obj, self ._private_name, self .default)
def __set__ (self , obj, value):
if value <= 0 :
raise ValueError (f"Value must be positive, got {value}" )
setattr (obj, self ._private_name, value)
class Product :
price = PositiveNumber()
quantity = PositiveNumber()
def __init__ (self , name, price, quantity):
self .name = name
self .price = price # 触发描述符的__set__
self .quantity = quantity
def total (self ):
return self .price * self .quantity
# 使用 -- 自动验证
p = Product("Laptop" , 999.99 , 5 )
print (p.total()) # 4999.95
try :
p.price = -100 # ValueError: Value must be positive, got -100
except ValueError as e:
print (e)
5.4 元类(Metaclass)
元类是创建类的类,是Python中最强大的元编程工具。适用于框架开发、ORM、API设计等场景。
# 元类 -- 控制类的创建
class RegistryMeta (type ):
"""元类:自动注册所有子类"""
registry = {}
def __new__ (mcs , name, bases, namespace):
cls = super ().__new__(mcs, name, bases, namespace)
if name != "BasePlugin" :
mcs.registry[name.lower()] = cls
return cls
class BasePlugin (metaclass =RegistryMeta):
"""所有插件的基础类"""
class PDFPlugin (BasePlugin):
def process (self , path):
return f"Processing PDF: {path}"
class ImagePlugin (BasePlugin):
def process (self , path):
return f"Processing Image: {path}"
# 所有子类自动注册
print (RegistryMeta.registry)
# {'pdfplugin': <class '__main__.PDFPlugin'>, 'imageplugin': <class '__main__.ImagePlugin'>}
# 元类应用:单例元类
class SingletonMeta (type ):
_instances = {}
def __call__ (cls , *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super ().__call__(*args, **kwargs)
return cls._instances[cls]
class Database (metaclass =SingletonMeta):
def __init__ (self ):
self .connected = False
重要提醒
元类是Python最强大的元编程工具,但也是最容易被滥用的工具。Python之禅说"Simple is better than complex",在90%的场景下,装饰器、描述符或继承都足以解决问题。需要元类时,往往是你在开发框架或库,而非应用程序。
六、设计模式选择指南
选择合适的设计模式往往比实现模式本身更具挑战。以下指南助你在Python项目中做出正确的模式选择。
6.1 快速选择矩阵
需求场景
推荐模式
Python实现建议
需要确保全局唯一实例
单例模式
模块级实例(最优先)、装饰器、元类
对象创建逻辑复杂
工厂模式
工厂函数、字典注册表
构建复杂对象需分步骤
建造者模式
链式调用 + dataclass
需要运行时动态添加职责
装饰器模式
函数装饰器、类装饰器
算法需要运行时互换
策略模式
一等函数(lambda或函数引用)
对象状态改变时通知多个依赖
观察者模式
回调函数列表、信号库
需要顺序访问聚合对象
迭代器模式
生成器(yield/yield from)
对象行为依赖其内部状态
状态模式
枚举 + 字典派发表
为复杂子系统提供简化接口
外观模式
封装类(Facade)
控制对对象的访问
代理模式
__getattr__转发、描述符
需要对象或资源自动清理
上下文管理器
__enter__/__exit__协议
需要属性级别的验证控制
描述符
描述符协议
6.2 何时不需要设计模式
如果Python有内置方案,就不要用GoF模式:
需要单例 → 用模块,不要写Singleton类
需要迭代器 → 用生成器,不要实现Iterator接口
需要装饰者 → 用@decorator,不要包装类
需要策略 → 用函数/lambda,不要策略类层次
需要工厂 → 用函数/类方法,不要工厂类
需要命令 → 用函数/functools.partial,不要命令类
需要观察者 → 用回调列表/信号,不要Observer接口
需要资源管理 → 用上下文管理器,不要手动try/finally
6.3 选择原则
Python模式选择五原则
Pythonic优先: 标准库提供了解决方案时,优先使用标准库
简单优先: 函数能解决的问题,不要引入类
组合优先: 优先使用组合而非继承
显式优于隐式: 模式的使用应该让代码意图更清晰,而非更模糊
模式是手段不是目的: 为了使用模式而重构,往往适得其反
"设计模式是你的工具箱,不是你的建筑设计蓝图。知道什么时候不使用模式,和知道什么时候使用模式同样重要。"
七、核心要点总结
GoF模式在Python中的核心思想: 利用Python动态特性(一等函数、鸭子类型、协议、元编程)大幅简化GoF模式的实现,许多模式可以降维到函数调用级别
创建型模式: 模块单例替代Singleton、函数工厂替代Factory Method、dataclass+链式调用简化Builder、copy模块支持Prototype
结构型模式: 鸭子类型简化Adapter、装饰器语法原生支持Decorator、__getattr__简化Proxy、lru_cache实现Flyweight缓存
行为型模式: 一等函数替代Strategy/Observer/Command、生成器实现Iterator、枚举+派发表简化State、函数列表实现Chain of Responsibility
Python特有模式: 可调用对象、上下文管理器、描述符、元类是Python语言独有的设计模式,应熟练掌握
选择指南: Pythonic优先、简单优先、组合优先 -- 当Python已有内置方案时,不需要"手动实现"GoF模式
八、进一步思考与实践
设计模式的学习不应止步于记忆UML类图和实现方法。真正的掌握来自于在实战中体会模式背后的设计原则。以下是一些建议:
学习路径建议
阅读源码: 阅读知名Python框架源码(如Requests、Flask、Click、SQLAlchemy),分析它们使用了哪些模式
重构练习: 将自己过去写的代码用模式思想重构,体会模式带来的是简化还是复杂化
理解而非记忆: 重要的是理解每个模式解决了什么"问题",而非记住实现代码
跨语言对比: 比较同一模式在Java/C++和Python中的实现差异,理解语言特性对模式的影响
关注反模式: 识别和避免Python中的常见反模式(如滥用元类、过度设计)
实践项目推荐
用策略模式+观察者模式构建一个交易信号系统
用组合模式+访问者模式构建文件系统分析工具
用状态模式+职责链模式构建订单处理工作流
用上下文管理器+描述符构建带重试和超时控制的数据库连接池
用元类+工厂模式构建一个插件自动发现系统
本笔记为Python设计模式综合实践学习笔记,基于GoF 23种设计模式及Python特有设计模式整理总结
本学习笔记为本人学习资料,不得转载
免责声明: 本学习笔记只供学习使用,代码示例仅供参考。设计模式是解决方案的思路,而非唯一实现方式。