目录

  1. 单例模式简介
  2. 单例模式的结构
  3. 单例模式的优缺点
  4. 单例模式的实现
    • 4.1 Python 经典实现
    • 4.2 线程安全的单例
    • 4.3 基于 __new__ 方法的实现
    • 4.4 基于 metaclass 的实现
  5. 单例模式的应用场景
  6. 出站链接
  7. 站内链接
  8. 参考资料

1. 单例模式简介

单例模式(Singleton Pattern) 是一种创建型设计模式,用于确保一个类只有一个实例,并提供全局访问点

为什么使用单例模式?

  • 全局唯一性:确保某个类只有一个实例,防止创建多个实例导致数据不一致。
  • 节省资源:多个组件共享相同实例,避免重复创建对象,减少内存占用。
  • 控制访问:可用于管理全局状态,例如日志管理器、数据库连接池、配置管理等。

2. 单例模式的结构

单例模式主要包含以下两个核心角色

角色作用
单例类(Singleton)负责创建唯一实例,并提供访问方法
客户端(Client)通过单例类获取唯一实例

UML 类图

┌───────────────┐
│   Singleton   │
├───────────────┤
│ - instance    │
│ + get_instance() │
└───────────────┘
        ▲
        │
  ┌─────┴─────┐
  │  Client   │


3. 单例模式的优缺点

优点

  1. 确保全局唯一实例,防止多个对象导致状态不一致。
  2. 减少资源消耗,避免重复创建实例,提高系统性能。
  3. 提供全局访问点,简化对象管理,方便维护。

缺点

  1. 可能引入全局状态,使代码难以测试和维护,影响模块化设计。
  2. 多线程环境下可能引发并发问题,需要额外的同步机制。
  3. 隐藏类的依赖关系,可能增加代码的耦合性。

4. 单例模式的实现

4.1 Python 经典实现

class Singleton:
    _instance = None  # 存储唯一实例

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance

# 测试
obj1 = Singleton()
obj2 = Singleton()

print(obj1 is obj2)  # True,两个对象是同一个实例

📌 关键点

  • 通过 _instance 变量存储唯一实例。
  • __new__ 方法控制实例的创建,保证只有一个实例。

4.2 线程安全的单例

多线程环境下可能会导致多个实例的创建,需要加锁

import threading

class Singleton:
    _instance = None
    _lock = threading.Lock()  # 线程锁

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            with cls._lock:  # 确保线程安全
                if not cls._instance:
                    cls._instance = super().__new__(cls)
        return cls._instance

# 测试
def test_singleton():
    obj = Singleton()
    print(obj)

threads = [threading.Thread(target=test_singleton) for _ in range(5)]
for t in threads:
    t.start()
for t in threads:
    t.join()

📌 关键点

  • 通过 threading.Lock() 确保只有一个线程能创建实例
  • 双重检查锁避免重复创建实例,提高效率。

4.3 基于 __new__ 方法的实现

更简洁的方式

class Singleton:
    _instances = {}

    def __new__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__new__(cls)
        return cls._instances[cls]

# 测试
obj1 = Singleton()
obj2 = Singleton()
print(obj1 is obj2)  # True

📌 关键点

  • 通过 dict 维护不同类的单例实例,支持多个不同的单例类

4.4 基于 metaclass(元类)的实现

使用元类(Metaclass)创建单例,更加 Pythonic

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 Singleton(metaclass=SingletonMeta):
    def __init__(self, value):
        self.value = value

# 测试
obj1 = Singleton("A")
obj2 = Singleton("B")
print(obj1.value, obj2.value)  # A A
print(obj1 is obj2)  # True

📌 关键点

  • 元类(metaclass)控制类的实例化过程,确保所有对象都是同一实例。
  • 适用于更复杂的单例需求,如继承、组合模式

5. 单例模式的应用场景

单例模式适用于全局唯一对象管理的场景,例如:

  1. 数据库连接池
    • 维护唯一的数据库连接,避免重复连接浪费资源。
  2. 日志记录器
    • 统一管理日志记录,确保日志格式和存储一致。
  3. 配置管理器
    • 维护全局配置信息,确保多个模块共享相同配置。
  4. 缓存管理
    • 维护全局缓存实例,减少不必要的计算和数据库查询。
  5. 操作系统资源管理
    • 确保某些资源(如打印机、文件系统)只有一个管理类。

6. 出站链接

7. 站内链接

8. 参考资料

  • Gamma, E., Design Patterns: Elements of Reusable Object-Oriented Software (1994).
  • Martin, R. C., Clean Code: A Handbook of Agile Software Craftsmanship (2009).

总结

  • 单例模式确保类只有一个实例,适用于全局资源管理
  • 经典 __new__ 方法、线程安全、元类 metaclass 都是常见的实现方式。
  • 适用于日志、数据库连接池、配置管理等场景,但不适用于所有情况,避免过度使用影响代码可维护性。

如果你有具体的应用场景,想要深入优化实现,欢迎讨论!🚀