• 设计模式之单例模式


    一、理解单例模式

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

    单例的模式的意图如下:

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

      实现单例模式的一个简单方法是,使构造函数私有化,并创建一个静态方法来完成对象的初始化。这样,对象将在第一次调用时创建,此后,这个类将返回同一个对象。然后在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
  • 相关阅读:
    (4.7)怎么捕获和记录SQL Server中发生的死锁?
    SQLSERVER排查CPU占用高的情况
    (4.6)sql server索引缺失提示
    (4.14)向上取整、向下取整、四舍五入取整的实例
    mysql大致学习路径
    (2)linux未使用eth0,未使用IPV4导致无法连接
    (4.13)sql server参数嗅探(parameter sniffing)
    完美女人
    关于box-sizing
    什么是担当
  • 原文地址:https://www.cnblogs.com/shenjianping/p/11070767.html
Copyright © 2020-2023  润新知