Skip to content

单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。比如在 Windows 系统中,任务管理器就是单例模式的应用,无论在系统的任何地方调用任务管理器,都是同一个实例。

使用场景

  • 数据库连接池
  • 日志记录器
  • 配置管理器
  • 线程池
  • 缓存系统

通过 __new__方法控制实例化推荐

class Singleton:
    _instance = None  # 类属性保存唯一实例

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            # 首次创建实例时调用基类的 __new__
            cls._instance = super().__new__(cls)
        return cls._instance  # 始终返回同一个实例

    def __init__(self, config):
        # 防止重复初始化
        if not hasattr(self, '_initialized'):
            self.config = config
            self._instance = True


# 使用示例
s1 = Singleton(config='DB_config')
s2 = Singleton(config='New_config')
print(s1 is s2)
print(s1.config)

True
New_config

装饰器

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 Logger:
    def __init__(self, log_file):
        self.log_file = log_file


logger1 = Logger('app.log')
logger2 = Logger('new.log')
print(logger1 is logger2)
print(logger1.log_file)

True
app.log

通过元类

# 方法3 通过元类
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 DatabaseConnection(metaclass=SingletonMeta):
    def __init__(self, connection_string):
        self.conn = self._connect(connection_string)

    def _connect(self, conn_str):
        print(f'Connecting to {conn_str}...')
        return 'Connection object'


# 使用示例
db1 = DatabaseConnection("mysql://user:pwd@localhost")
db2 = DatabaseConnection("postgres://user:pwd@localhost")
print(db1 is db2)  # 输出: True
print(db1.conn)  # 输出: "Connection Object"

Connecting to mysql://user:pwd@localhost...
True
Connection object
  1. 定义单例类,重写__new__方法,确保只创建一个实例。
  2. 在类的初始化方法__init__中检查是否已初始化,避免重复初始化。
  3. 提供示例代码,展示如何创建实例并验证其唯一性。
  4. 简要讨论其他实现方式,如使用装饰器或元类。
  5. 提及线程安全和其他注意事项