单例模式业务场景及实现的几种方式
1.业务场景
windows的回收站其实就是一个单例,你双击第二次并不会在出现一个出现窗口,对象只会创建一次
第三方sdk做接口发送短信验证码,如果有几十万个用户同时发送短信,只需调用对象的方法即可
我们一般在调用数据库的时候也采用单例模式来实现的,这样避免了内存空间不必要的占用和浪费
2.文件导入的形式
模块在第一次导入时,会生成 .pyc
文件,当第二次导入时,就会直接加载 .pyc
文件,而不会再次执行模块代码。
这个其实在django中的admin组件用到过,自己编写相关组件时候,相当的有用
s1.py class Foo(object): def test(self): print("123") v = Foo() #v是Foo的实例 s2.py from s1 import v as v1 # 第一次导入,实例化并放进内存
s3.py from s1 import v as v2 # 第二次导入直接从内存中获取
2.基于类实现
2.1 基于__new__方法实现
常见模式1:
class B: __instance = None def __new__(cls, *args, **kwargs): if cls.__instance is None: cls.__instance = object.__new__(cls) return cls.__instance def __init__(self,name,age): self.name = name self.age = age a = B('alex',80) b = B('egon',20) print(a) print(b) print(a.name) print(b.name) # <__main__.B object at 0x04F1D330> # 结果相同 # <__main__.B object at 0x04F1D330> # egon # egon
常见模式2:
class A: def __new__(cls, *args, **kwargs): if not hasattr(cls,'instance'): # 每次实例化,都返回这同一个对象 cls.instance = super().__new__(cls) return cls.instance obj1 = A() obj2 = A() obj1.attr = 'value' print(obj1.attr) print(obj2.attr) # value # value
2.2 与线程相关
不支持多线程:
class Singleton(object): def __init__(self): import time time.sleep(1) @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance import threading def task(arg): obj = Singleton.instance() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start()
支持多线程:
import time import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(1) @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: #为了保证线程安全在内部加锁 if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance def task(arg): obj = Singleton.instance() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start() time.sleep(20) obj = Singleton.instance() print(obj) # 使用先说明,以后用单例模式,obj = Singleton.instance() # 示例: # obj1 = Singleton.instance() # obj2 = Singleton.instance() # print(obj1,obj2) # 错误示例 # obj1 = Singleton() # obj2 = Singleton() # print(obj1,obj2)
3.通过装饰器实现
def wrapper(cls): instance = {} def inner(*args,**kwargs): if cls not in instance: instance[cls] = cls(*args,**kwargs) return instance[cls] return inner @wrapper class Singleton(object): def __init__(self,name,age): self.name = name self.age = age obj1 = Singleton('尼古拉斯',99) obj2 = Singleton('蓝恩',19) print(obj1) print(obj2)