Python 设计模式实战:单例与工厂模式详解
在软件开发领域,设计模式(Design Pattern)是一套被广泛认可的解决方案,用于解决特定情境下重复出现的软件设计问题。它们提供了一种标准化的语言,帮助开发者提高代码的可读性、可维护性和可扩展性。Python 作为一种高级动态编程语言,凭借其简洁的语法和强大的元编程能力,为设计模式的实现提供了多种灵活的方式。
详细讲解了 Python 中两种常用的设计模式:单例模式和工厂模式。单例模式确保类只有一个实例,提供了模块级和类级别(含线程安全)的实现方案,适用于日志、配置等共享资源场景。工厂模式通过解耦对象创建与使用,简化了复杂对象的实例化过程,包括简单工厂和抽象工厂两种变体,配合字典映射优化了扩展性。文章通过代码示例分析了各模式的优缺点及适用场景,强调了在 Python 开发中选择合适模式以提升代码可维护性和扩展性的重要性。

在软件开发领域,设计模式(Design Pattern)是一套被广泛认可的解决方案,用于解决特定情境下重复出现的软件设计问题。它们提供了一种标准化的语言,帮助开发者提高代码的可读性、可维护性和可扩展性。Python 作为一种高级动态编程语言,凭借其简洁的语法和强大的元编程能力,为设计模式的实现提供了多种灵活的方式。
本文将深入探讨两种最常用的创建型设计模式:单例模式(Singleton Pattern)和工厂模式(Factory Pattern)。我们将通过具体的 Python 代码示例,分析它们的实现原理、适用场景以及潜在陷阱,帮助你编写更加优雅和健壮的代码。
单例模式确保一个类在整个应用程序生命周期中只有一个实例,并提供一个全局访问点。这种模式常用于需要共享资源的场景,例如数据库连接池、日志记录器、配置管理器等。
在 Python 中,实现单例模式有多种方式,从隐式的模块级单例到显式的类控制。
Python 的模块系统天然支持单例特性。当一个模块被导入时,它只会被执行一次,其中的全局变量或对象在后续导入中会复用同一个引用。
# logger.py
import logging
class Logger:
def __init__(self):
self.log = []
def add_log(self, message):
self.log.append(message)
def print_log(self):
for message in self.log:
print(message)
# 在全局作用域实例化
logger = Logger()
在其他模块中直接 import logger 即可使用 logger.logger 实例。由于模块加载机制,这保证了唯一性。这种方式简单高效,是 Python 中最推荐的'隐式'单例写法。
如果需要更严格的控制,或者需要在类内部管理状态,可以使用 __new__ 方法重写对象的创建过程。
import threading
class SingletonLogger:
_instance = None
_lock = threading.Lock()
def __new__(cls):
# 双重检查锁定(Double-Checked Locking)
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.log = []
return cls._instance
def add_log(self, message):
self.log.append(message)
def print_log(self):
for message in self.log:
print(message)
关键点解析:
threading.Lock)来防止多个线程同时进入实例化逻辑。双重检查锁定(Double-Checked Locking)是一种优化手段,减少锁的开销。_instance.log = [] 应在 __new__ 中赋值,而不是 __init__ 中,因为 __init__ 可能在每次调用构造函数时被触发(取决于具体实现),而 __new__ 才是真正分配内存的地方。优点:
缺点:
工厂模式是一种创建型设计模式,它定义了创建对象的接口,但将具体的实例化逻辑推迟到子类或工厂函数中。其核心目的是解耦客户端代码与具体产品类的依赖关系,符合开闭原则(Open/Closed Principle)。
简单工厂由一个工厂类根据参数决定创建哪种产品对象。虽然简单,但它违反了开闭原则,因为添加新产品需要修改工厂类的逻辑。
class Calculator:
def calculate(self, a, b):
pass
class AddCalculator(Calculator):
def calculate(self, a, b):
return a + b
class SubtractCalculator(Calculator):
def calculate(self, a, b):
return a - b
class CalculatorFactory:
@staticmethod
def create_calculator(operator):
if operator == "+":
return AddCalculator()
elif operator == "-":
return SubtractCalculator()
else:
raise ValueError("Invalid operator")
# 使用示例
calc = CalculatorFactory.create_calculator("+")
print(calc.calculate(10, 5))
为了减少 if-elif 语句并提高扩展性,可以使用字典映射来替代条件判断。
class CalculatorFactory:
calculators = {
"+": AddCalculator,
"-": SubtractCalculator
}
@staticmethod
def create_calculator(operator):
if operator in CalculatorFactory.calculators:
return CalculatorFactory.calculators[operator]()
else:
raise ValueError("Invalid operator")
这种方式将类名存储在字典中,新增运算符只需在字典中添加一行,无需修改工厂方法逻辑。
当系统需要创建一系列相关或依赖的对象,而不希望指定具体类时,抽象工厂模式非常有用。它提供了一个接口,用于创建相关对象的家族。
from abc import ABC, abstractmethod
class CalculatorFactory(ABC):
@abstractmethod
def create_calculator(self):
pass
class AdditionCalculatorFactory(CalculatorFactory):
def create_calculator(self):
return AdditionCalculator()
class SubtractionCalculatorFactory(CalculatorFactory):
def create_calculator(self):
return SubtractionCalculator()
class Calculator(ABC):
@abstractmethod
def calculate(self, num1, num2):
pass
class AdditionCalculator(Calculator):
def calculate(self, num1, num2):
return num1 + num2
class SubtractionCalculator(Calculator):
def calculate(self, num1, num2):
return num1 - num2
def create_calculator(operator):
if operator == "+":
factory = AdditionCalculatorFactory()
elif operator == "-":
factory = SubtractionCalculatorFactory()
else:
raise ValueError("Invalid operator")
return factory.create_calculator()
优点:
缺点:
Factory 结尾,具体产品类应明确表达其功能。设计模式不是银弹,而是工具箱中的利器。在实际开发中,应根据项目规模、团队习惯和维护成本权衡是否使用。掌握单例和工厂模式的核心思想,能够帮助我们构建出结构清晰、易于维护的高质量 Python 应用。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online