美文网首页
失效的单例模式

失效的单例模式

作者: Yucz | 来源:发表于2020-09-16 00:00 被阅读0次

简书上为首发,拒绝抄袭,原文地址 https://www.jianshu.com/p/a7f1e58f5ee6

失效的单例模式

Python的单例模式实现方法有很多种,其中有一种是基于 __new__ 和让子类去继承的实现方法。但是根据我的踩坑经验,这种方法往往是有问题的。试了下网上的多种实现方法,都有问题! 这种实现的单例并不是真正的单例! 这种实现在单线程中都存在问题,更别说在复杂的多线程环境中了

代码实现

我们就拿 stackoverflow高赞回答作分析(网上的其他回答都大同小异),其中所提到的 基于 __new__ 的实现代码如下

class Singleton(object):
  _instances = {}
  def __new__(class_, *args, **kwargs):
    if class_ not in class_._instances:
        class_._instances[class_] = \
        super(Singleton, class_).__new__(class_, *args, **kwargs)
    return class_._instances[class_]

class MyClass(Singleton):
  pass

c = MyClass()

实现的原理在于,控制子类的 __new__ 方法,让其返回的都是同一个对象

初步测试

我们不妨写一些测试代码去分析

class A(Singleton):
    def __init__(self):
        self.test_list = []

a = A()
b = A()
c = A()

a.test_list.append('a')
b.test_list.append('b')
c.test_list.append('c')

print(id(a), id(b), id(c))
print(a is b and b is c)
print("a.test_list =", a.test_list)
print("b.test_list =", b.test_list)
print("c.test_list =", c.test_list)

输出

140072986470664 140072986470664 140072986470664
True
a.test_list = ['a', 'b', 'c']
b.test_list = ['a', 'b', 'c']
c.test_list = ['a', 'b', 'c']

输出的确是正常的,我们可以看出 ab 以及 c 都是同一对象。并且我们后续分别往 abc 中的 test_list 都存入数据后,每个实例的 test_list 都是 ['a', 'b', 'c'], 这就是我们想要的结果!

但这是否意味着这个单例的实现没问题呢?我们再做如下实验

进一步测试

我们把对每个实例的 test_list 插入顺序,改成实例化完,立马插入

看下结果会怎样,测试代码如下

class A(Singleton):
    def __init__(self):
        self.test_list = []

a = A()
a.test_list.append('a')
b = A()
b.test_list.append('b')
c = A()
c.test_list.append('c')

print(id(a), id(b), id(c))
print(a is b and b is c)
print("a.test_list =", a.test_list)
print("b.test_list =", b.test_list)
print("c.test_list =", c.test_list)

输出

140373892725000 140373892725000 140373892725000
True
a.test_list = ['c']
b.test_list = ['c']
c.test_list = ['c']

这时我们就发现问题了!

abc 还是同一个对象,但是我们往 ab 中塞进的数据竟然不见了,最终的 test_list 只有 c ! 单例失效了! 这个单例的实现有问题!

原因分析

这个问题出现的原因就在于使用 __new__ 实现的 Singlegon ,只会控制子类的 __new__ 实现,而不会控制子类的 __init__ 的实现

当我们的子类自实现 __new__ 方法时,每一次实例化子类,虽然子类的 __new__ 确保最终只会实例化一次,但是 __new__ 执行完后,子类还会执行自己的 __init__ 方法,当__init__ 中存在属性时,属性就会被多次声明,最终新生成的属性会覆盖掉上一次生成的属性!

我们可以针对上述的代码加一些打印进行跟踪

代码如下

class A(Singleton):
    def __init__(self):
        self.test_list = []
        print("id(test_list) =", id(self.test_list))

a = A()
a.test_list.append('a')
b = A()
b.test_list.append('b')
c = A()
c.test_list.append('c')

print("id(a.test_list) =", id(a.test_list))
print("id(b.test_list) =", id(a.test_list))
print("id(c.test_list) =", id(c.test_list))

print("a.test_list =", a.test_list)
print("b.test_list =", b.test_list)
print("c.test_list =", c.test_list)

输出

id(test_list) = 139866765387336 # a 的 test_list 
id(test_list) = 139866765389512 # b 的 test_list
id(test_list) = 139866765387336 # c 的 test_list
id(a.test_list) = 139866765387336 # 打印的是 c 的 test_list
id(b.test_list) = 139866765387336 # 打印的是 c 的 test_list
id(c.test_list) = 139866765387336 # 打印的是 c 的 test_list
a.test_list = ['c']
b.test_list = ['c']
c.test_list = ['c']

我们可以看出,在 __init__ 中打印 id(self.test_list) 时,执行了三次,说明 __init__ 方法执行了三次

并且 每个实例的 id(test_list) 是不一样的,可以看出 self.test_list 确实被定义了三次

而在 a b c 实例化完成后,我们再去打印每个实例的 id(test_list) 时,发现 abtest_list 的 id 竟然变成和 c 一致,即 ab 中的 test_list 被覆盖了,原先的各自的内容都丢失了!

这明显不符合单例模式的应用场景! 单例模式的这种实现有 BUG!

总结
  • 单例模式不要使用基于 __new__ 的实现

相关文章

  • 失效的单例模式

    简书上为首发,拒绝抄袭,原文地址 https://www.jianshu.com/p/a7f1e58f5ee6[h...

  • 第二章 IPC机制

    多进程会造成哪些问题① 静态成员和单例模式失效② 线程同步机制完全失效③ SharedPreferences 的可...

  • IPC进程间通信(开发艺术探索)

    使用多进程造成的问题 静态成员和单例模式完全失效 线程同步机制完全失效 SharedPreferences的可靠性...

  • 多进程哪些会失效

    静态成员和单例模式会失效,因为进程内存空间相互独立,所以虚拟机内的静态方法区的静态变量也是互相独立。由于单例模式是...

  • Android——AIDL使用

    一、作用 二、概念 1. 多进程带来的问题 静态成员和单例模式完全失效 线程同步机制失效 SharedPrefer...

  • 【设计模式】单例模式

    单例模式 常用单例模式: 懒汉单例模式: 静态内部类单例模式: Android Application 中使用单例模式:

  • 多进程开发

    多进程的缺点: 1. 静态成员和单例模式的完全失效。 2. 线程同步机制完全失效。 3. SharePrefere...

  • Android设计模式总结

    单例模式:饿汉单例模式://饿汉单例模式 懒汉单例模式: Double CheckLock(DCL)实现单例 Bu...

  • Telegram开源项目之单例模式

    NotificationCenter的单例模式 NotificationCenter的单例模式分析 这种单例模式是...

  • 设计模式之单例模式详解

    设计模式之单例模式详解 单例模式写法大全,也许有你不知道的写法 导航 引言 什么是单例? 单例模式作用 单例模式的...

网友评论

      本文标题:失效的单例模式

      本文链接:https://www.haomeiwen.com/subject/honqyktx.html