设计模式之单例模式

一、理解单例模式

  确保类有且只有一个特定类型的对象,并提供全局访问点,单例模式通常用于下列情形,例如日志记录或数据库操作等,避免对同一资源请求的相互冲突。

单例的模式的意图如下:

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

  实现单例模式的一个简单方法是,使构造函数私有化,并创建一个静态方法来完成对象的初始化。这样,对象将在第一次调用时创建,此后,这个类将返回同一个对象。然后在python中构造函数是无法私有化的,因此需要使用其他方式进行创建。

二、实现

1、基于__new__方法创建单例

  __new__方法是先于__init__方法执行,主要用于创建对象,在完成单例模式时,主要是:只允许单例类生成一个实例;如果已经有一个实例了,重复提供同一个对象。这样保证每一次实例化类只提供一个对象。

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()
print(s)

s1=SingleTon()
print(s1)

###输出###########
#<__main__.SingleTon object at 0x0000000000656828>
#<__main__.SingleTon object at 0x0000000000656828>

  上面是通过覆盖__new__的方法创建对象的,对象s就是由__new__方法创建的,但是在创建之前会先检查cls中是否已经有一个对象(instance就是对象),如果没有就创建一个实例,如果已经存在,就将已经存在的实例进行返回。

  s1对象在使用__new__方法创建时,会通过hasattr属性检查是否已经存在对象实例,此时已经存在s的实例,所以将s的实例地址返回给s1。

2、基于getInstance创建单例

  为了避免对内存造成浪费,直到需要实例化该类的时候才将其实例化,所以用getInstance来获取该对象。

class SingleTon(object):

    _instance=None

    def __init__(self):
        if not SingleTon._instance:
            print("没有创建对象")
        else:
            print("已经创建对象",self.getInstance())
    @classmethod
    def getInstance(cls):
        if not cls._instance:
            cls._instance=SingleTon()
        return cls._instance

s=SingleTon() #并没有创建对象

SingleTon.getInstance()  #创建了对象
s1=SingleTon() #对象已经存在
#####################输出############
#没有创建对象
#没有创建对象
#已经创建对象 <__main__.SingleTon object at 0x0000000000676898>

  当执行s=SingleTon()执行了__init__方法,然而并没有创建对象,真正创建对象的是在SingleTon.getInstance(),这样每次在获取对象时就通过这个静态方法获取,不需要使用__new__方法来创造对象。

3、基于模块级别的单例模式

  python导入模块的行为决定了每一个模块都是单例,因为,python在导入模块时会检查模块是否已经导入,如果没有导入,它会进行导入并且实例化,如果已经导入则会返回该模块的对象。

  因此,当模块被导入的时候,它就会被初始化。然而,当同一个模块被再次导入的时候,它不会再次初始化,因为单例模式只能有一个对象,所以,它会返回同一个对象。

使用方式:

  • 在一个py文件中写入类并且实例化
class AdminSite(object):

    def __init__(self):
        pass

site=AdminSite()
  • 在另一个py文件中导入该类对象
from base_moudle.base import site

print(site) #<base_moudle.base.AdminSite object at 0x0000000000D3AE80>

4、基于元类创建单例

  在python中 一切皆对象,由class关键字创建的类也应该是一个对象,那么,既然是对象,它也应该是由类来创建的,这个类就叫做元类(type)。当通过一个元类来创建一个类时,比如当使用类A创建一个类时,pytno通过A=type(name,bases,dict)创建它。

  • name:这是类的名称。
  • base:这是基类。
  • dict:这是属性变量。

比如使用元类创建一个类:

class MyString(type):#继承type才是一个元类

    def __call__(self, *args, **kwargs):

        return type.__call__(self,*args, **kwargs)

class String(metaclass=MyString):

    def __init__(self,x):
        self.x=x

s=String("abggd")

  当需要创建对象时,将调用__call__方法,也就是说对象()触发__call__方法的执行,当对String类进行实例化时,实际是MyString元类的对象进行实例化,这会触发__call__方法的运行,它的返回值就是实例化后的结果的接收值,这意味者元类控制着对象的实例化。

  同样的,也就可以利用以上的思路,进行单例模式的实现,为了控制类的创建和初始化,元类将覆盖__new__以及__init__方法。

class MetaSingleTon(type):

    _instance={}
    def __call__(self, *args, **kwargs): #self指代的是传过来的类 AdminSite
        if self not in self._instance:
            self._instance[self]=super(MetaSingleTon,self).__call__( *args, **kwargs)
        return self._instance[self]

class AdminSite(metaclass=MetaSingleTon):
    pass

a1=AdminSite() #相当于执行元类中的__call__方法,__call__的返回值是什么a1就是什么
print(a1)
a2=AdminSite()
print(a2)

########输出###########
#<__main__.AdminSite object at 0x0000000000666CC0>
#<__main__.AdminSite object at 0x0000000000666CC0>

单例模式可以应用于多种场景,这里提供应用于数据库层面的,保证数据库操作一致性以及提高内存利用率。

import pymysql
class MetaSingleTon(type):

    _instance={}
    def __call__(self, *args, **kwargs): #self指代的是传过来的类 AdminSite
        if self not in self._instance:
            self._instance[self]=super(MetaSingleTon,self).__call__( *args, **kwargs)
        return self._instance[self]

class DataBase(metaclass=MetaSingleTon):

    connection=None
    def connect(self):

        if self.connection is None:
            self.connection=pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root', db='test', charset='utf8')
            self.cursor=self.connection.cursor()
        return self.cursor

    def excute(self,sql):
        pass

    def close(self):
        self.connect().close()
        self.connection.close()

db1=DataBase()
db2=DataBase()
print(db1)
print(db2)
#########################输出################
#<__main__.DataBase object at 0x0000000000DF6A90>
#<__main__.DataBase object at 0x0000000000DF6A90>
操作数据库

 5、Monostate单例模式

  它与Singleton单例模式是有不同之处的,Singleton关注的是一个类有且只有一个对象,而Monostate关注的则是一个类不管有多少个对象,所有的对象只有一个状态,因此它也被称为单态模式。那么它是如何实现这种模式呢?

class Borg:

    __shared_state={}

    def __init__(self):
        self.x=3
        self.__dict__=self.__shared_state

b1=Borg()
b2=Borg()
b2.x=4

print(b1.__dict__)
print(b2.__dict__)
######输出###########
#{'x': 4}
#{'x': 4}

  将__shared_state变量作为一个中间变量,并且赋值给python中存储类所有对象状态的__dict__变量,这在实例后,会产生两个不同的对象,但是b1.__dict__和b2.__dict__都指向了__shared_state的内存地址。

  另外还可以通过__new__来实现单态模式:

class Borg:

    __shared_state = {}

    def __new__(cls, *args, **kwargs):
        obj=super(Borg,cls).__new__(cls, *args, **kwargs)
        obj.__dict__ = obj.__shared_state
        return obj
原文地址:https://www.cnblogs.com/shenjianping/p/11070767.html