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

6.0 KiB
Raw Permalink Blame History

技术文档:单例模式装饰器与全局环境管理


概述

本文档介绍了基于 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))  # 输出: HAHAme HAHAme

尽管两次构造传参不同,但由于单例机制,d 实际上是 c 的引用,name 仍为 'me'

e = Handle('hammer')
f = Handle('nail')

print(str(e), str(f))  # 假设实现了 __str__否则会报错

同样地,fe 是同一实例,最终输出取决于 Handle 是否重写了字符串方法。


输出结果分析

运行上述测试代码的实际输出为:

child.init
HAHAme HAHAme
HAHAme HAHAme

因为 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)           # 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

推荐在生产环境中使用修正版本以避免常见陷阱。