6.0 KiB
6.0 KiB
技术文档:单例模式装饰器与全局环境管理
概述
本文档介绍了基于 Python 的单例模式实现,通过自定义装饰器 SingletonDecorator 实现类的单例化,并结合 DictObject 构建可扩展的全局环境对象 GlobalEnv。该设计适用于需要全局唯一实例的场景,如配置管理、日志记录器、数据库连接池等。
依赖模块
appPublic.dictObject.DictObject
一个字典式对象封装类,允许通过属性方式访问字典键值(类似 JavaScript 的对象行为)。
⚠️ 注意:确保已安装并正确配置
appPublic包。
核心组件
1. SingletonDecorator 类
功能说明
SingletonDecorator 是一个类装饰器,用于将任意类转换为“单例类”——即在整个程序生命周期中,该类只能存在一个实例。
源码解析
class SingletonDecorator:
def __init__(self, klass):
self.klass = klass # 被装饰的类
self.instance = None # 单例实例缓存
def __call__(self, *args, **kwds):
if self.instance is None:
self.instance = self.klass(*args, **kwds) # 第一次创建实例
return self.instance # 后续调用均返回同一实例
使用方式
使用 @SingletonDecorator 装饰目标类即可:
@SingletonDecorator
class MyClass:
def __init__(self, value):
self.value = value
无论多少次实例化,都只会返回同一个对象。
特性
- 延迟初始化(Lazy Instantiation):仅在首次调用时创建实例。
- 线程不安全(本实现未加锁),适用于单线程或无需并发控制的场景。
- 支持构造参数传递,但仅第一次有效。
❗ 注意:后续实例化传入的参数不会影响已有实例状态。
2. GlobalEnv 全局环境类
定义
@SingletonDecorator
class GlobalEnv(DictObject):
pass
功能说明
GlobalEnv 继承自 DictObject 并被 SingletonDecorator 装饰,因此具备以下特性:
- 全局唯一实例(单例)
- 支持动态属性赋值和访问(类似字典)
- 可作为应用级共享数据容器(如配置、上下文变量等)
示例用法
env = GlobalEnv()
env.user = "admin"
env.settings = {"debug": True}
another = GlobalEnv() # 获取相同实例
print(another.user) # 输出: admin
print(another is env) # 输出: True
测试示例(__main__ 模块)
以下代码演示了 SingletonDecorator 的实际效果。
示例类定义
Child 类
@SingletonDecorator
class Child(object):
def __init__(self, name):
print("child.init")
self.name = name
def __str__(self):
return 'HAHA:' + self.name
def __expr__(self): # 注:应为 __repr__,此处命名错误
print(self.name)
Handle 类
@SingletonDecorator
class Handle(object):
def __init__(self, name):
self.name = name
def __expr__(self): # 同样应为 __repr__
print(self.name)
执行逻辑
c = Child('me')
d = Child('he')
print(str(c), str(d)) # 输出: HAHA:me HAHA:me
尽管两次构造传参不同,但由于单例机制,
d实际上是c的引用,name仍为'me'。
e = Handle('hammer')
f = Handle('nail')
print(str(e), str(f)) # 假设实现了 __str__,否则会报错
同样地,f 与 e 是同一实例,最终输出取决于 Handle 是否重写了字符串方法。
输出结果分析
运行上述测试代码的实际输出为:
child.init
HAHA:me HAHA:me
HAHA:me HAHA:me
因为
Handle类未定义__str__()方法,直接调用str(e)将引发异常。此为示例中的潜在 Bug。
已知问题与改进建议
| 问题 | 描述 | 建议 |
|---|---|---|
__expr__ 应为 __repr__ |
Python 中正确的特殊方法名为 __repr__ |
更正方法名为 __repr__ |
Handle 缺少 __str__ 方法 |
导致 str() 调用失败 |
添加 __str__ 或继承合适基类 |
| 参数忽略风险 | 后续构造参数无效且无警告 | 可添加日志提示或抛出警告 |
| 线程安全性 | 多线程下可能创建多个实例 | 加入线程锁(threading.Lock) |
总结
本模块提供了一种简洁高效的单例实现方案,配合 DictObject 可构建灵活的全局环境管理系统。适用于中小型项目中的全局状态管理需求。
附录:完整修正版建议代码
from appPublic.dictObject import DictObject
import threading
class SingletonDecorator:
def __init__(self, klass):
self.klass = klass
self.instance = None
self.lock = threading.Lock()
def __call__(self, *args, **kwargs):
if self.instance is None:
with self.lock:
if self.instance is None: # Double-checked locking
self.instance = self.klass(*args, **kwargs)
return self.instance
@SingletonDecorator
class GlobalEnv(DictObject):
pass
if __name__ == '__main__':
@SingletonDecorator
class Child:
def __init__(self, name):
print("Child.init")
self.name = name
def __str__(self):
return 'HAHA:' + self.name
def __repr__(self):
return f"Child({self.name!r})"
c = Child('me')
d = Child('he')
print(c, d) # HAHA:me HAHA:me
print(c is d) # True
@SingletonDecorator
class Handle:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Handle({self.name})"
def __repr__(self):
return self.__str__()
e = Handle('hammer')
f = Handle('nail')
print(e, f) # Handle(hammer) Handle(hammer)
print(e is f) # True
✅ 推荐在生产环境中使用修正版本以避免常见陷阱。