目录
概念理解
单例模式要保证一个类在整个系统运行期间,无论创建多少次该类的对象,始终只会有一个实例存在。就像操作系统中的任务管理器,无论何时何地调用它,都是同一个任务管理器在工作,不会同时出现多个不同的任务管理器实例
使用场景
- 资源共享:当多个模块需要共享同一个资源时,使用单例模式可以避免资源的重复创建和浪费。例如,数据库连接池,使用单例模式可以确保所有模块使用的同一个数据库连接池,避免了 多个连接池的创建,提高了资源的利用率
- 日志记录器:在一个应用程序中,通常只需要一个日志记录器来记录系统的运行信息。使用单例模式可以确保所有模块都使用同一个日志记录器,避免了日志信息的分散和混乱
- 配置管理:在一个系统中,配置信息通常是全局的,并且只需要一份。使用单例模式中可以确保所有模块都使用同一个配置对象,方便对配置信息进行统一管理和修改
优缺点
优点
- 节省资源:由于只创建一个实例,减少了系统资源的开销,特别是对于一些创建和销毁开销较大的对象,如数据库连接、文件系统等。
- 全局访问:提供了一个全局访问点,方便其他模块获取该实例,避免了在多个地方重复创建对象。
- 数据一致性:由于所有模块都使用同一个实例,保证了数据的一致性和完整性。
缺点 - 违反单一职责原则:单例模式的类既负责创建实例,又负责管理实例的生命周期,违反了单一职责原则。
- 扩展性差:由于单例模式的类只有一个实例,难以进行扩展和修改。如果需要对单例类进行扩展,可能需要修改原有的代码,不符合开闭原则。
- 多线程问题:在多线程环境下,如果没有进行适当的同步处理,可能会导致多个线程同时创建实例,破坏单例模式的唯一性。
实现方式
懒汉式(线程不安全)
bash
class Singleton:
_instance = None
@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = cls()
return cls._instance
# 使用示例
s1 = Singleton.get_instance()
s2 = Singleton.get_instance()
print(s1 is s2) # 输出: True
这种方式在第一次调用 get_instance 方法时才创建实例,但在多线程环境下可能会创建多个实例。
懒汉式(线程安全)
bash
import threading
class Singleton:
_instance = None
_lock = threading.Lock()
@classmethod
def get_instance(cls):
with cls._lock:
if cls._instance is None:
cls._instance = cls()
return cls._instance
# 使用示例
s1 = Singleton.get_instance()
s2 = Singleton.get_instance()
print(s1 is s2) # 输出: True
通过加锁的方式保证在多线程环境下也只会创建一个实例,但每次获取实例都需要加锁,会影响性能。
饿汉式
bash
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
# 使用示例
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # 输出: True
这种方式在类加载时就创建实例,避免了多线程问题,但如果实例创建过程比较耗时,会影响系统的启动性能。