能否部分实现Singleton模式?按参数返回相同/不同实例的方案探讨
实现同参数返回单实例的方案
你要的是基于参数的实例缓存——相同参数调用类时返回同一个实例,不同参数返回不同实例。不用搞两个类,有更简洁的实现方式:
方案一:重写类的__new__方法(推荐)
直接在目标类内部通过重写创建实例的__new__方法实现缓存,调用方式和你示例里完全一致:
class SomeClass: # 用类变量存储缓存的实例 _instance_cache = {} def __new__(cls, *args, **kwargs): # 把位置参数和关键字参数组合成唯一键 # 注意:kwargs转成frozenset是为了避免字典顺序影响键的唯一性 key = (args, frozenset(kwargs.items())) # 缓存里没有就创建新实例并存入 if key not in cls._instance_cache: cls._instance_cache[key] = super().__new__(cls) # 标记实例未初始化,避免重复执行__init__ cls._instance_cache[key]._initialized = False instance = cls._instance_cache[key] # 只在第一次创建时执行初始化 if not getattr(instance, '_initialized', False): instance.__init__(*args, **kwargs) instance._initialized = True return instance def __init__(self, arg1, arg2, arg3): self.arg1 = arg1 self.arg2 = arg2 self.arg3 = arg3
测试代码
arg1 = 1 arg2 = 2 arg3 = 3 arg4 = 4 arg5 = 5 instance1 = SomeClass(arg1, arg2, arg3) instance2 = SomeClass(arg1, arg4, arg5) instance3 = SomeClass(arg1, arg2, arg3) print(id(instance1) == id(instance2)) # 输出 False print(id(instance1) == id(instance3)) # 输出 True
方案二:用装饰器包装类
如果不想修改类的内部代码,可以写一个通用装饰器来实现实例缓存:
def cached_instance(cls): cache = {} def wrapper(*args, **kwargs): key = (args, frozenset(kwargs.items())) if key not in cache: cache[key] = cls(*args, **kwargs) return cache[key] return wrapper # 给目标类加上装饰器 @cached_instance class SomeClass: def __init__(self, arg1, arg2, arg3): self.arg1 = arg1 self.arg2 = arg2 self.arg3 = arg3
这个方案的调用方式和测试结果和上面完全一致,而且装饰器可以复用给其他类。
关于你提到的双类方案
双类(工厂类+目标类)的方式也能实现,但需要通过工厂方法调用(比如SomeClassFactory.get_instance(...)),不如上面两种方案直接,而且代码冗余度更高,所以不推荐。
内容的提问来源于stack exchange,提问作者Saprophytex
相关产品推荐
相关产品推荐

