设计模式可以分为三大类:创建型,结构型和行为型模式。单例设计模式是应用程序开发过程中最简单和最著名的一种创建型设计模式。
1. 理解单例设计模式
单例模式确保了这样一个机制,确保类有且只有一个特定类型的对象,并提供全局访问点。用于以下场景:日志记录或数据库操作,打印机后台处理程序等--该程序运行过程中只能生成一个实例,以避免对同一资源产生相互冲突的请求。例如,我们可能希望使用一个数据库对象对数据库操作,以维护数据的一致性;或者希望使用一个日志类的对象,将多项服务的日志信息按照顺序存储到一个特定的日志文件中。
简而言之,单例设计模式的意图如下:
- 确保类有且只有一个对象被创建
- 为对象提供一个访问点,以使程序可以全局访问该对象
- 控制共享资源的并行访问
实现单例模式的一个简单方法是,使构造函数私有化,并创建一个静态方法来完成对象的初始化。这样,对象将在第一次调用时创建,此后这个类将返回同一个对象。
2. Python实现经典的单例模型
以下时Python3的单例模式实现代码,主要完成两项工作:
- 只允许Singleton类生成一个实列
- 如果已经有一个实例了,会重复提供同一个对象
class Singleton(object):
def __new__(cls):
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
if __name__ == '__main__':
s = Singleton()
print('Object created', s)
s1 = Singleton()
print('Object created', s1)
先详细说明一下__new__方法,__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供。__new__必须要有返回值,返回实例化出来的实例,这点在实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例。_init__的参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值。若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的。
上述代码中,对象s是由__new__方法创建的,但在创建之前,该方法会检查对象是否已存在。方法hasattr查看类cls是否具有instance属性,如果具有该属性,说明已经生成了一个对象实例,便不再创建新的对象,而是返回这个已有的对象。
3. 单例模式的懒汉式实例化
单例模式的用处之一就是懒汉式实例化,例如,在导入一个模块时,会创建一些对象,但我们有时并不会用到其中一些对象。为了节约资源,懒汉式实例化能够确保在实际需要时才创建对象。
如下代码中,执行s = Singleton()的时候,会调用__init__方法,但并没有新的对象被创建。实际的创建发生在调用Singleton.getInstance()的时候。
class Singleton:
__instance = None
def __init__(self):
if not Singleton.__instance:
print('__init__ method called...')
else:
print('Instance already created:', self.getInstance())
@classmethod
def getInstance(cls):
if not cls.__instance:
cls.__instance = Singleton()
return cls.__instance
if __name__ == '__main__':
s = Singleton() # Class initialized, but object not created
print('Object created', Singleton.getInstance()) # Object gets created here
s1 = Singleton() # Instance already created
4. 模块级别的单例模式
默认情况下,所有的模块都是单例的,这是由python的导入行为来决定的。
python通过以下方式来工作
- 检查一个python模块是否被导入
- 如果已经导入,则返回该模块的对象。如果还没有导入,则导入该模块并实例化
- 因此,当一个模块被导入的时候,它就会初始化。当同一模块被再次导入时,它不会被再次初始化,因为单例模式只有一个对象,它将会返回同一个对象