单例模式
单例模式(Singleton),是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。
采用单例模式动机、原因
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
优点:
- 只创建一个实例对象,节省内存
- 便于外界访问,加快对象访问速度
缺点:
- 不适用于频繁变化的对象
- 如果实例化的对象长时间不被利用,系统会认为这是垃圾而进行回收,这可能导致对象状态的丢失。
实现单例模式
方法一:重新__new__方法(__new__方法负责创建对象)
class singleton(object):
__instance=None
def __new__(cls, *args, **kwargs):
if cls.__instance==None:
cls.__instance=object.__new__(cls) #如果没有实例,重写父类的__new__
return cls.__instance
else:
return cls.__instance
obj1=singleton()
obj2=singleton()
print(id(obj1))
print(id(obj2))
执行结果:
1885817379640
1885817379640
方法二:调用装饰器
def singleton(cls,*args,**kwargs):
instanse={}
def _singleton():
if cls not in instanse:
instanse[cls]=cls(*args,**kwargs)
return instanse[cls]
return _singleton
@singleton
class Myclass(object):
pass
obj1=Myclass()
obj2=Myclass()
print(id(obj1)) #2334021295240
print(id(obj2)) #2334021295240
方法三:使用模块,python的模块是单例模块,因为模块在第一次导入时,会生成.pyc文件,当第二次导入时,就会直接加载.pyc文件,而不会再次执行模块代码。因此我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
#mysingleton.py
class singleton(object):
def foo(self):
print('hh')
obj=singleton()
#daoru.py
from mysingleton import obj
obj.foo()
print(id(obj)) #2207001701792
from mysingleton import obj
obj.foo()
print(id(obj)) #2207001701792