python单例模式的实现,重写__new__()方式以及利用metaclass方法与闭包两种方式实现单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场

单例模式的设计思想:
1.饿汉式:先有对象,如果要获取对象,直接把对象返回
    采用:空间换取时间
2.懒汉式:只有在获取对象的时候,会首先判断对象是否存在
    如果对象不存在,创建一个对象病返回,如果对象存在则直接返回该对象
    采用:时间换取空间

python中不支持先创建对象,后在定义类的方式,因此python中没有用饿汉式实现单例模式的代码,只存在懒汉式实现单例模式,下面的重写__new__方式以及利用metaclass方法和闭包都是通过懒汉式的思想实现。一些其他的语言可以利用饿汉式的设计思想实现单例模式

【优点】
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。

【缺点】
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期

不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用

单例模式的简单理解

1 单例模式 只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等
2 单例的缺点 就是不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
用单例模式,就是在适用其优点的状态下使用

使用__new__方法实现单例模式,代码如下:

class Car:

    #创建单例标识
    instance = None
    #因为只创建一个对象,所以判断是否存在对象
    isCreate = False
    def __new__(cls,brand,color,wheel):
        #创建对象,产生对象,判断标识是否存在
        if Car.instance == None:
            Car.instance = super().__new__(cls)
        return Car.instance

    #初始化属性数据
    def __init__(self,brand,color,wheel):
	# 根据Car.isCreate判断是否已经实例化对象,若第一为False,则认定为Car类为进行初始化操作,初始化操作进行之后,
	# Car.isCreate则改变为True
        if Car.isCreate == False:
            self.brand = brand
            self.color = color
            self.wheel = wheel
            #创建属性之后修改成已被创建
            Car.isCreate = True

    def show(self):
        print(self.brand,self.color,self.wheel)

c1 = Car("大奔","黑色",4)
c1.show()
print(id(c1))

c2 = Car("奥迪","银色",4)
c2.show()
print(id(c2))

下图为程序运行结果,两次运行的结果一致,实现单例

利用metaclass方法与闭包实现单例模式,代码如下:

def signten(classname,bases,dicts):
    # 设置标志,判断是否初始化
    _instance = None

    # 返回的是类对象
    s = None
    def get_instance(name,age):
        nonlocal s
        if s == None:
            # 实例化,元类的使用
            # classmate,bases,dicts为元类type的三个参数
            _instance = type(classname,bases,dicts)
            # s为类_instance的对象
            s = _instance(name,age)
        return s
    # 闭包必须返回参数,参数为方法名,不可返回方法名()
    # 引用函数,并非调用函数,返回的是函数对象
    return get_instance

# 此时的User为方法,并非类,User()这时是在调用函数,并非类
class User(metaclass=signten):
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
    def __str__(self):
        return f"name:{self.name},age:{self.age}"

# print(User)
# 上面语句的结果如下,返回的是一个函数,而类
# <function signten.<locals>.get_instance at 0x0000027FB0920268>
#  通过函数Uesr(),并返回get_instance()函数的返回值
u = User("王",23)
u1 = User("郭",15)
print(u is u1)

程序代码运行如下:结果和利用__new__方式一样,但是区别在于:metaclass方法的使用改变了程序的运行结构,而闭包的存在,则延长了变量的存活周期。

猜你喜欢

转载自blog.csdn.net/qq_41292236/article/details/94588932