单例模式
单例模式(Singleton):
单例设计模式是应用开发过程中最简单和最著名的一种创建型设计模式。
单例模式提供了这样一种机制,即确保类有且只有一个特定类型的对象,并提供全局访问点。因此,单例模式通常用于下列情形,例如日志记录或数据库操作、打印机后台处理程序,以及其他程序------该程序运行过程中只能生成一个实例,以避免对同一资源产生相互冲突的请求。例如:
- 我们可能希望使用一个数据库对象对数据库进行操作,以维护数据的一致性;
- 或希望使用一个日志类对象,将多项服务的日志信息按照顺序转储到一个特定的日志文件中。
简言之,单例设计模式的意图如下:
- 确保类有且只有一个对象被创建。
- 为对象提供一个访问点,以使程序可以全局访问该对象。
- 控制共享资源的并行访问。
实现单例模式的一个简单方法是,使构造函数私有化,并创建一个静态方法来完成对象的初始化。这样,对象将在第一次调用时创建,此后,这个类将返回同一个对象。在使用Python的时候,我们的实现方式要有所变通,因为它无法创建私有的构造函数。
利用Python 实现经典的单例模式
下面是基于Python v3.5 的单例模式实现代码,它主要完成了两件事情。
- 只允许Singleton 类生成一个实例。
- 如果已经有一个实例了,我们会重复提供同一个对象。
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls.instance
测试:
>>> s = Singleton() >>> s <__main__.Singleton object at 0x000001E9087BFEF0> >>> >>> s1 = Singleton() >>> s1 <__main__.Singleton object at 0x000001E9087BFEF0> >>>
在上面的代码中,我们通过覆盖 __new__ 方法 (Python 用于实例化对象的特殊方法)来控制对象的创建。对象 s 就是由 __new__ 方法创建的,但是在创建前,该方法会检查对象是否已存在。
方法 hasattr (Python 的特殊方法,用来了解对象是否具有某个属性)用于查看对象 cls 是否具有属性 instance,该属性的作用是检查该类是否已经生成一个对象。当 对象 s1被请求的时候,hasattr() 发现对象已经存在,所以,对象 s1 将被分配已有的对象实例(地址位于 0x000001E9087BFEF0 )。
单例模式中的懒汉式实例化
单例模式的用途之一就是懒汉式实例化。例如,在导入模块的时候,我们可能会无意中创建一个对象,但当时根本用不上它。懒汉式实例化能够确保在实际需要时才创建对象。所以,懒汉式实例化是一种节约资源并且仅在需要时才创建它们的方式。
在下面的代码示例中,执行 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
测试:
>>> s = Singleton() # class initialized, but object not created __init__ method called.. >>> >>> Singleton.getInstance() # Object gets created here __init__ method called.. <__main__.Singleton object at 0x000001E9087BFF60> >>> >>> s1 = Singleton() # instance already created Instance already created: <__main__.Singleton object at 0x000001E9087BFF60> >>>
模块级别的单例模式
默认情况下, 所有的模块都是单例,这是由 Python 的导入行为所决定的。
Python 通过下列方式来工作。
- 检查一个 Python 模块是否已经导入。
- 如果已经导入,则返回该模块的对象。如果还没有导入,则导入该模块,并实例化。
- 因此,当模块被导入的时候,它就会被初始化。
- 然而,当一个模块被再次导入的时候,他不会再次初始化,因为单例模式只能有一个对象,所以它会返回同一个对象
单例模式的经典使用场景:
- 资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
- 控制资源的情况下,方便资源之间的互相通信。如线程池等。
应用场景举例:
- 外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。
- 内部资源:大多数软件都有一个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件
- Windows的Task Manager(任务管理器)就是很典型的单例模式
- windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
- 网站的计数器,一般也是采用单例模式实现,否则难以同步。
- 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
- Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。
- 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
- 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
- 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
- HttpApplication 也是单位例的典型应用。熟悉ASP.Net(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式, 所有的HttpModule都共享一个HttpApplication实例.

浙公网安备 33010602011771号