经典设计模式之单例模式(Python实现)

设计模式是由GoF(Gang of Four)首先提出的,根据他们的观点来看,设计模式就是解决特定问题的解决方案。在原著作者的经典著作中,使用了Java语言提供了23中设计模式的设计和实现。设计模式本身是一种发现,而不是一种发明。
设计模式的主要特点如下:

  • 它们是语言无关的,可以用多种语言实现。
  • 它们是动态的,随时会有新的模式引入。
  • 它们可以进行定制,因此对开发人员非常有用。

常用的设计模式可以大致分为三大类,分别是:

  • 创造型模式
  • 结构型模式
  • 行为型模式

本文中详细介绍的单例模式属于创造型模式中的一种。
单例设计模式是应用开发过程中最简单和最著名的一种创造型设计模式。它提供了这样一种机制,即确保类有且只有一个特定类型的对象,并提供全局访问点。因此,单例模式通常适用于下列情形:

  1. 日志记录以及数据库操作
  2. 打印机后台处理程序
  3. 程序运行过程中只需要生成一个实例的情况等…

它可以避免对同一资源产生相互冲突的请求。例如,我们可能希望使用一个数据库对象来对数据库进行操作,以维护数据的一致性;或者希望使用一个日志类的对象,将多项服务的日志信息按照顺序转储到一个特定的日志文件中等…简言之,单例模式的设计意图主要如下:

  • 确保类有且只有一个对象被创建
  • 为对象提供一个全局访问点,以使程序可以全局访问该对象
  • 控制共享资源的并行访问

实现单例模式的一个简单方法是,是构造函数私有化,并创建一个静态方法来完成对象的初始化。这样,对象将在第一次调用时创建,此后,这个类将返回同一个对象。但是在Python中,因为无法创建私有的构造函数,所以在这里我们实现的方式需要稍微有所变通。在Python3.7环境下,快速实现单例模式代码如下:

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, 'instance'):
            cls.instance = super(Singleton, cls).__new__(cls)
        return cls.instance


s1 = Singleton()
print('Object created', s1)

s2 = Singleton()
print('Object created', s2)

代码输出结果如下:

Object created <__main__.Singleton object at 0x107d42780>
Object created <__main__.Singleton object at 0x107d42780>

我们可以看到,两次分别创建类的实例时,返回的却是同一个对象。new()是Python的特殊方法,用于实例化一个类(这里稍微有些绕口,不清楚的同学百度一下Python的__new__方法具体含义,这里就不过多介绍了)。hasattr方法则是检验对象是否具有某个属性,这里用于查看对象cls是否具有属性instance,设置该属性的作用是为了检测类是否已经生成了一个对象。当对象s2被请求时,hasattr()发现对象已经存在,因此s2被分配到已有的对象实例s1,地址位于0x107d42780。
在日常的使用中,单例模式经常会使用到懒汉式实例化的情形。例如,在导入模块的时候,我们可能会无意中创建一个对象,但当时根本用不到它。懒汉式实例化能够确保在实际需要时才创建对象,所以,懒汉式实例化是一种节约资源并仅在需要时才创建它们的方式。
下面提供单例模式的懒汉式实例化的代码实现。

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


s1 = Singleton()
print('Object created', Singleton.getInstance())
s2 = Singleton()

代码输出如下:

__init__method called...
__init__method called...
Object created <__main__.Singleton object at 0x1043f9630>
Instance already created: <__main__.Singleton object at 0x1043f9630>

在上面的代码中,在执行s1=Singleton()的时候,它会调用__init__方法,但没有新的对象被创建。实际的对象创建发生在调用Singleton.getInstance()的时候,我们正是通过这种方式来实现懒汉式实例化的。

总结

  • 在许多实际应用中,我们只需要创建一个对象,比如线程池、缓存、对话框、注册表设置等,如果我们为每个应用程序创建多个实例,则会导致资源的过度使用。单例模式在这种情况下工作得很好。
  • 单例是一种经过时间考验的成熟方法,能够在不带来太多缺陷的情况下提供全局访问点。
  • 单例模式也存在其局限性,例如:1.全局变量可能在某处已经被修改,但是开发人员仍然认为它们没有发生变化,而该变量还在应用程序的其他位置被使用。2.可能会对同一个对象创建多个引用。由于单例模式只能创建一个对象,因此这种情况下会对同一个对象创建多个引用。3.所有依赖于全局变量的类都会由于一个类的改变而紧密耦合为全局数据,从而可能会在无意中影响另一个类。

猜你喜欢

转载自blog.csdn.net/airenKKK/article/details/96189702