设计模式(一):单例模式

一,什么是单例模式

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

适用场景——该程序运行过程中只能生成一个实例,以避免对同一资源产生相互冲突的请求
- 需要一个全局唯一的对象来协调整个系统的行为,如配置管理器,统一管理系统配置。
- 资源共享的情况,如共享的数据库连接池,使用一个数据库对象对数据库进行操作,以维护数据的一致性。
- 控制资源的情况,如管理打印机的使用。
- 日志记录器(Logger):通常在应用程序中只需要一个日志实例,仅使用一个日志类的对象,将多项服务的日志信息按照顺序转储到一个特定的日志文件中。

总之,单例模式的意图就是:
- 确保类有且只有一个对象被创建。
- 为对象提供一个访问点,以使程序可以全局访问该对象。
- 控制共享资源的并行访问。

二,python 代码

(一)最简单的实现

实现单例模式的一个简单方法:

class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            # 初始化代码可以放在这里
        return cls._instance

    def some_business_logic(self):
        # 单例的业务逻辑方法
        pass


# 使用示例
s1 = Singleton()
s2 = Singleton()

print(s1 is s2)  # 输出: True
  • 使用 __new__ 方法来控制实例的创建。
  • 通过 hasattr(cls, '_instance') 检查类是否已经有一个实例。
  • 如果没有实例,就创建一个新的实例并保存在类属性 _instance 中。
  • 返回这个唯一的实例。

(二)提高灵活性

改进一下代码:改进版本主要是为了提高代码的可读性和灵活性

# 原始版本
class Singleton(object):
    _instance = None

    def __new__(cls):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance


# 改进版本
class SingletonImproved:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            # 初始化代码可以放在这里
        return cls._instance

    def __init__(self):
        # 初始化代码
        if not hasattr(self, 'initialized'):
            self.initialized = True
            # 其他初始化代码...

    def some_business_logic(self):
        # 单例的业务逻辑方法
        pass


# 使用示例
s1 = SingletonImproved()
s2 = SingletonImproved()
print(s1 is s2)  # 输出: True
  • 使用类变量 _instance = None 来存储实例,这样更加明确和易读。
  • 使用 is None 检查而不是 hasattr,这样更加直观和高效。
  • 添加了 __init__ 方法来处理初始化逻辑。
  • __init__ 中使用一个标志来确保初始化代码只运行一次。

(三)带初始化参数

对于需要参数化的单例,可以实现一个带参数的 __new__ 方法:

class ParameterizedSingleton:
    _instances = {
   }

    def __new__(cls, *args, **kwargs):
        # 将位置参数和关键字参数组合成一个不可变的 key,用作实例的唯一标识
        key = (args, frozenset(kwargs.items()))
        
        # 检查是否已经存在对应的实例
        if key not in cls._instances:
            cls._instances[key] = super().__new__(cls)
        
        return cls._instances[key]

    def __init__(self, *args, **kwargs):
        # 确保 __init__ 只被调用一次
        if not hasattr(self, 'initialized'):
            self.args = args
            self.kwargs = kwargs
            self.initialized = True
            print(f"Initializing with args: {
     args} and kwargs: {
     kwargs}")

    def get_parameters(self):
        return self.args, self.kwargs



# 创建第一个实例
instance1 = ParameterizedSingleton(10, name="test1")
print(instance1.get_parameters())  # 输出: ((10,), {'name': 'test1'})

# 创建第二个实例,参数不同
instance2 = ParameterizedSingleton(20, name="test2")
print(instance2.get_parameters())  # 输出: ((20,), {'name': 'test2'})

# 创建与第一个实例相同参数的实例
instance3 = ParameterizedSingleton(10, name="test1")
print(instance3.get_parameters())  # 输出: ((10,), {'name': 'test1'})

# 检查单例特性
print(instance1 is instance3)  # 输出: True
print(instance1 is instance2)  # 输出: False

这个版本:

  • 参数化:可以基于不同的参数创建不同的单例实例。
  • 灵活性:可以easily扩展到多个参数。
  • 内存效率:只为独特的参数组合创建新实例。

(四)线程安全

上面的代码都不是线程安全的:

# 线程不安全的单例实现
class ThreadUnsafeSingleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            time.sleep(0.1)  # 模拟耗时操作
            cls._instance = super().__new__(cls)
        return cls._instance

线程不安全的原因:

  • 在多线程环境中,多个线程可能同时执行到 if cls._instance is None 这一行。
  • 如果这些线程同时发现 _instance 为 None,它们都会尝试创建新实例。
  • 这可能导致多个实例被创建,违反了单例模式的核心原则。

线程不安全将导致的问题:

  • 多个实例:不同线程可能最终使用不同的实例,导致状态不一致。
  • 资源浪费:创建多个不必要的实例可能会浪费资源。
  • 不可预测的行为:依赖单例的代码可能会因为使用了不同的实例而表现出意外行为。

这里就用锁来改进:

import threading
import time

# 线程不安全的单例实现
class ThreadUnsafeSingleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            time
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值