一、前言:为什么 Python 也需要设计模式?
Python 是动态语言,语法灵活,不需要像 Java 那样严格,但在 Python 开发中也需要用到设计模式。虽然 Python 的特性(如一等函数、装饰器、鸭子类型)简化了许多模式的实现,但设计模式的核心思想是"解耦"、"复用"和"可维护性"。在大型项目、团队协作或复杂业务逻辑中,良好的设计模式能避免代码变成一坨...
在 Python 中应用设计模式时,应遵循 KISS (Keep It Simple, Stupid) 原则,不要为了模式而模式。
二、 创建型模式 (Creational Patterns)
创建型模式关注对象的创建过程,将对象的创建与使用分离。
2.1 单例模式 (Singleton)
场景:确保一个类只有一个实例,并提供全局访问点。例如:数据库连接池、配置管理器。
Pythonic 实现 : 在 Python 中,模块本身就是单例的。最简单的单例是直接写在模块里。如果必须用类,可以使用元类或 __new__。
# 方法一:使用装饰器实现单例
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class Database:
def __init__(self):
print("Initializing Database Connection...")
db1 = Database()
db2 = Database()
print(db1 is db2) # 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 Config(metaclass=SingletonMeta):
pass
2.2 工厂模式 (Factory)
场景:不需要知道具体类的实例化细节,只需根据参数获取对象。
简单工厂示例:
class Dog:
def speak(self): return "Woof!"
class Cat:
def speak(self): return "Meow!"
class AnimalFactory:
@staticmethod
def get_animal(animal_type):
if animal_type == 'dog':
return Dog()
elif animal_type == 'cat':
return Cat()
else:
raise ValueError("Unknown animal type")
# 使用
animal = AnimalFactory.get_animal('dog')
print(animal.speak())
注:Python 中常利用多态和字典映射来简化工厂逻辑,避免大量的 if-else。
2.3 建造者模式 (Builder)
场景:构建复杂对象,步骤固定但内部表示可能变化。例如:构建复杂的 HTTP 请求对象、SQL 查询构建器。
class House:
def __init__(self):
self.walls = None
self.roof = None
self.rooms = None
def __str__(self):
return f"House with {self.walls} walls, {self.roof} roof, {self.rooms} rooms"
class HouseBuilder:
def __init__(self):
self.house = House()
def set_walls(self, walls):
self.house.walls = walls
return self
def set_roof(self, roof):
self.house.roof = roof
return self
def set_rooms(self, rooms):
self.house.rooms = rooms
return self
def build(self):
return self.house
# 链式调用
house = HouseBuilder().set_walls(4).set_roof("Tile").set_rooms(3).build()
print(house)
三、 结构型模式 (Structural Patterns)
结构型模式关注类和对象的组合,形成更大的结构。
3.1 装饰器模式 (Decorator)
场景 :动态地给对象添加职责。 Python 特性 :Python 语言原生支持装饰器语法 (@),这是装饰器模式的一等公民。
# 函数装饰器
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_decorator
def say_hello():
print("Hello")
say_hello()
# 类装饰器模式 (用于扩展类功能)
class TextField:
def write(self, text):
print(text)
class BorderDecorator:
def __init__(self, component):
self._component = component
def write(self, text):
print("-----")
self._component.write(text)
print("-----")
# 使用
text = TextField()
bordered_text = BorderDecorator(text)
bordered_text.write("Content")
3.2 适配器模式 (Adapter)
场景:接口不兼容,需要转换。例如:对接第三方 API,旧代码复用。
# 目标接口
class Target:
def request(self):
return "Target: The default target's behavior."
# 需要适配的类
class Adaptee:
def specific_request(self):
return ".eetpaAd ehT :eetpadA"
# 适配器
class Adapter(Target):
def __init__(self, adaptee):
self.adaptee = adaptee
def request(self):
return f"Adapter: (TRANSLATED) {self.adaptee.specific_request()[::-1]}"
# 使用
adaptee = Adaptee()
adapter = Adapter(adaptee)
print(adapter.request())
3.3 外观模式 (Facade)
场景:为子系统提供统一的入口,降低耦合。例如:封装复杂的视频转换流程。
class CPU:
def freeze(self): print("Freezing CPU")
def jump(self): print("Jumping to address")
class Memory:
def load(self): print("Loading data")
class SSD:
def read(self): print("Reading from SSD")
class ComputerFacade:
def __init__(self):
self.cpu = CPU()
self.memory = Memory()
self.ssd = SSD()
def start(self):
print("Starting Computer...")
self.cpu.freeze()
self.memory.load()
self.ssd.read()
self.cpu.jump()
print("Computer Started.")
# 客户端只需调用一个方法
pc = ComputerFacade()
pc.start()
四、 行为型模式 (Behavioral Patterns)
行为型模式关注对象之间的通信和责任分配。
4.1 策略模式 (Strategy)
场景 :定义一系列算法,把它们封装起来,并使它们可互换。Python 中常利用函数作为参数来简化策略模式。
from abc import ABC, abstractmethod
# 传统类实现
class Strategy(ABC):
@abstractmethod
def execute(self, data):
pass
class ConcreteStrategyA(Strategy):
def execute(self, data):
return sorted(data)
class ConcreteStrategyB(Strategy):
def execute(self, data):
return list(reversed(data))
class Context:
def __init__(self, strategy: Strategy):
self._strategy = strategy
def set_strategy(self, strategy: Strategy):
self._strategy = strategy
def run(self, data):
return self._strategy.execute(data)
# Pythonic 实现:直接传入函数
def sort_strategy(data): return sorted(data)
def reverse_strategy(data): return list(reversed(data))
def run_strategy(data, strategy_func):
return strategy_func(data)
print(run_strategy([3, 1, 2], sort_strategy))
4.2 观察者模式 (Observer)
场景:对象状态改变时,自动通知依赖对象。事件驱动系统的核心。
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def notify(self, message):
for observer in self._observers:
observer.update(message)
class Observer:
def update(self, message):
print(f"Received: {message}")
# 使用
subject = Subject()
obs1 = Observer()
obs2 = Observer()
subject.attach(obs1)
subject.attach(obs2)
subject.notify("New Data Available!")
注:实际生产中推荐使用 pubsub 库或信号量机制(如 Django Signals)。
4.3 模板方法模式 (Template Method)
场景:定义算法骨架,将具体步骤延迟到子类。
from abc import ABC, abstractmethod
class DataMiner(ABC):
def mine(self, path):
self.open_file(path)
data = self.extract_data()
self.analyze(data)
self.close_file()
def open_file(self, path):
print(f"Opening {path}")
def close_file(self):
print("Closing file")
@abstractmethod
def extract_data(self):
pass
@abstractmethod
def analyze(self, data):
pass
class CSVMiner(DataMiner):
def extract_data(self):
print("Extracting CSV data")
return "csv_data"
def analyze(self, data):
print(f"Analyzing {data}")
# 使用
miner = CSVMiner()
miner.mine("data.csv")
五、 Python 特有的"模式"与注意事项
在 Python 中应用设计模式,必须考虑语言特性,否则会产生"反模式"。
-
模块即单例 : 不需要写复杂的单例类。创建一个
config.py模块,在其他地方import config,该模块内的变量就是全局单例的。 -
鸭子类型 (Duck Typing) : 不需要严格的接口继承(Interface)。只要对象有
read()方法,它就是文件流。这减少了对适配器模式的部分需求。 -
一等函数 : 策略模式、命令模式在 Python 中通常直接传递函数或
lambda,而不是创建一堆策略类。 -
装饰器语法 : 日志、权限校验、缓存等功能,优先使用
@decorator,而不是手动实现装饰器模式类。 -
避免过度设计 : YAGNI (You Ain't Gonna Need It)。如果代码只有 50 行,不要强行套用工厂模式。当复制粘贴代码超过 3 次,或者逻辑变得难以测试时,再考虑重构引入模式。
六、总结与建议
设计模式不是银弹,而是工具箱。
-
初级开发者:先理解代码逻辑,能写出功能正确的代码。
-
中级开发者:识别代码中的"坏味道"(如重复代码、高耦合),尝试用简单的模式(如策略、装饰器)重构。
-
高级开发者 :根据业务场景权衡,知道什么时候不使用模式同样重要。
推荐学习路径:
-
阅读《Python 设计模式》(相关书籍)。
-
阅读优秀开源项目源码(如
Requests,Flask,Django),看它们如何运用模式。 -
在实际项目中小步重构,不要一次性重写。