apppublic/aidocs/Singleton.md
2025-10-05 11:23:33 +08:00

240 lines
6.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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