第2课设计模式_单例模式
热度🔥:117 免费课程
授课语音
单例模式(Singleton Pattern)
1. 介绍
单例模式是一种设计模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点来访问该实例。
单例模式的核心概念
- 唯一性:确保一个类只有一个实例。即使多个线程尝试创建该类的对象,也只会存在一个实例。
- 全局访问:单例模式提供一个全局访问点来获取这个唯一实例,通常通过静态方法实现,以便在任何地方都可以访问该实例。
- 延迟初始化:在一些实现中,单例实例在第一次被请求时才被创建,这样可以避免不必要的开销。这一过程称为延迟初始化(lazy initialization)。
单例模式的变体
- 懒汉式单例(Lazy Initialization):在第一次被访问时创建实例,优点是延迟初始化,但需要处理多线程环境下的同步问题。
- 饿汉式单例(Eager Initialization):在类加载时就创建实例,这种方式简单且线程安全,但如果实例创建的开销较大而应用从未使用该实例,则可能会造成资源浪费。
- 双重检查锁(Double-Check Locking):在多线程环境下,通过双重检查和锁机制来确保实例创建的线程安全性。通常结合
volatile
关键字使用以避免指令重排序带来的问题。 - 登记式单例(Registry-based Singleton):使用注册表管理单例实例。通过静态方法或其他机制从注册表中获取单例实例,适合需要支持动态实例管理的场景。
- 枚举单例(Enum Singleton):使用枚举类型实现单例模式,这是 Java 推荐的实现方式,能够确保线程安全,并防止反序列化攻击。
实际框架中的应用
单例模式在许多实际框架和系统中有广泛的应用。以下是一些常见的应用场景:
配置管理:许多框架中,配置管理类通常使用单例模式。例如,Django 的 settings 模块就是一个单例,确保配置在整个应用程序中是一致的。
数据库连接池:数据库连接池通常使用单例模式来管理连接。例如,SQLAlchemy 中的 Engine 对象通常作为单例使用,以确保数据库连接的高效管理。
日志记录:日志记录器通常使用单例模式来确保日志记录的一致性。例如,Python 的 logging 模块可以配置为单例,以便在整个应用程序中共享同一个日志记录器实例。
缓存系统:缓存系统如 Redis 或 Memcached 客户端通常使用单例模式,以确保缓存客户端在整个应用程序中只有一个实例,从而提高性能和资源利用率。
Flask 应用:在 Flask 框架中,应用实例通常作为单例使用。Flask 的 app 对象在整个应用程序中是唯一的,确保了路由和配置的一致性。
2. 代码案例
import threading
from enum import Enum
class SingletonExamples:
# 1. 饿汉式单例(Eager Initialization)
# 饿汉式单例在模块加载时就创建实例,确保线程安全。
# 适用于实例创建开销较小且不会造成资源浪费的场景。
class EagerSingleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls, *args, **kwargs)
cls._instance._initialize()
return cls._instance
def _initialize(self):
# 初始化实例变量
self.value = "EagerSingleton Value"
def show_value(self):
# 显示实例的值
print(f"EagerSingleton value: {self.value}")
# 2. 懒汉式单例(Lazy Initialization)
# 懒汉式单例在第一次使用时创建实例,需要处理线程安全的问题。
# 使用锁来确保线程安全。
class LazySingleton:
_instance = None
_lock = threading.Lock()
def __new__(cls, *args, **kwargs):
if cls._instance is None:
with cls._lock: # 确保线程安全
if cls._instance is None:
cls._instance = super().__new__(cls, *args, **kwargs)
cls._instance._initialize()
return cls._instance
def _initialize(self):
# 初始化实例变量
self.value = "LazySingleton Value"
def show_value(self):
# 显示实例的值
print(f"LazySingleton value: {self.value}")
# 3. 双重检查锁(Double-Check Locking)
# 双重检查锁在多线程环境下提供高效的单例实现方式。
# 使用双重检查锁减少锁的开销。
class DoubleCheckLockingSingleton:
_instance = None
_lock = threading.Lock()
def __new__(cls, *args, **kwargs):
if cls._instance is None:
with cls._lock: # 确保线程安全
if cls._instance is None:
cls._instance = super().__new__(cls, *args, **kwargs)
cls._instance._initialize()
return cls._instance
def _initialize(self):
# 初始化实例变量
self.value = "DoubleCheckLockingSingleton Value"
def show_value(self):
# 显示实例的值
print(f"DoubleCheckLockingSingleton value: {self.value}")
# 4. 登记式单例(Registry-based Singleton)
# 登记式单例使用一个注册表来管理单例实例。
# 适用于动态管理单例的场景。
class RegistrySingleton:
_registry = {}
def __new__(cls, key, *args, **kwargs):
if key not in cls._registry:
cls._registry[key] = super().__new__(cls, *args, **kwargs)
cls._registry[key]._initialize()
return cls._registry[key]
def _initialize(self):
# 初始化实例变量
self.value = "RegistrySingleton Value"
def show_value(self):
# 显示实例的值
print(f"RegistrySingleton value: {self.value}")
# 5. 枚举单例(Enum Singleton)
# 枚举单例是Python推荐的实现单例模式的方式,能够防止反序列化攻击,并确保线程安全。
class EnumSingleton(Enum):
# 定义唯一的枚举成员 INSTANCE,用于存储单例实例
INSTANCE = 1
def show_value(self):
# 打印实例变量的值
print(f"EnumSingleton value: {self.name}")
# 示例代码
if __name__ == "__main__":
# 1. 饿汉式单例
eager1 = SingletonExamples.EagerSingleton()
eager2 = SingletonExamples.EagerSingleton()
eager1.show_value()
print(f"Are both EagerSingleton instances the same? {eager1 is eager2}")
# 2. 懒汉式单例
lazy1 = SingletonExamples.LazySingleton()
lazy2 = SingletonExamples.LazySingleton()
lazy1.show_value()
print(f"Are both LazySingleton instances the same? {lazy1 is lazy2}")
# 3. 双重检查锁
double_check1 = SingletonExamples.DoubleCheckLockingSingleton()
double_check2 = SingletonExamples.DoubleCheckLockingSingleton()
double_check1.show_value()
print(f"Are both DoubleCheckLockingSingleton instances the same? {double_check1 is double_check2}")
# 4. 登记式单例
registry1 = SingletonExamples.RegistrySingleton("key1")
registry2 = SingletonExamples.RegistrySingleton("key1")
registry1.show_value()
print(f"Are both RegistrySingleton instances the same? {registry1 is registry2}")
# 5. 枚举单例
enum_singleton = SingletonExamples.EnumSingleton.INSTANCE
enum_singleton.show_value()
详细中文注释
- 类说明:每个单例实现类都有一个内部初始化方法,用于设置初始值。在每个
show_value
方法中打印该实例的值,以验证实例的唯一性。 - 示例代码:在主程序中,我们创建每种单例的两个实例并检查它们是否相同,以证明单例模式的有效性。每个实例调用
show_value
方法显示其值。