单例的使用
单例优点
1,单例只保留一个对象,可以减少系统资源开销。
2,提高创建速度,每次都获取已经存在的对象因此提高创建速度–全局共享对象。
3,单例在系统中只存在一个对象实例,因此任何地方使用此对象都是同一个对象避免多实例创建使用时产生的逻辑错误。
主要缺点
1、由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
2、单例类的职责过重,在一定程度上违背了“单一职责原则”。
3、滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
# 方案一
# 单列基本实现步骤
# _单下划线,保护变量,意思是只有类对象和子类对象能够访问到这些变量(尽量避免在类外部直接修改)
class Singleton(object):
"""
单列类
"""
# 1.重写__new__ 注意:在类的__init__方法之前调用
def __new__(cls, *args, **kwargs):
# hasattr(类名,属性名) 判断类中是否有该属性
# 第一次创建类的对象
# Singleton类中没有_instance属性
# 第二Singleton()创建对象
if not hasattr(cls, '_instance'):
# 调用父类的__new__创建对象,并且将_instance属性保存到Singleton中
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
# 第二次直接返回类中对象
return cls._instance
# 方案二
# 线程安全的单列装饰器实现
from threading import Lock
def singleton(cls):
# 字典
instances = {}
# 锁对象
instances_lock = Lock()
def wrapper(*args, **kwargs):
# Person 不在字典中
if cls not in instances:
with instances_lock:
# {"类名": 类的对象}
# {"Person": Person()}
instances[cls] = cls(*args, **kwargs)
# 下一次直接返回对象
return instances[cls]
return wrapper
@singleton
class Person(object):
pass
if __name__ == '__main__':
s1 = Singleton()
s2 = Singleton()
print(s1)
print(s2)
p1 = Person()
p2 = Person()
print(p1)
print(p2)
使用场景 --> 数据库链接用单例, (云通讯,七牛云的SDK配置的封装)
在实际项目中,可能会在多个不同的方法中使用MySQL链接,如果每次都新建、关闭连接,当访问量高时可能会造服务器崩溃无法访问等问题,而单例模式可以很好的解决这个问题。
每次都需要发网络请求跟云通讯对接,由于有网络延迟的问题,如果每次请求就要验证一次,会影响项目的运行效率,使用单例只需要验证一次,下次连接时就不需要再次验证,从而增加了用户的体验。