美文网首页程序员
Python中单例模式的实现

Python中单例模式的实现

作者: 小餐包 | 来源:发表于2020-05-22 09:35 被阅读0次

最近在看《head first design mode》,提到经典的单例模式的Java实现:

public class SingleTon {
    private static SingleTon uniqueInstance;

    private SingleTon() {
    }

    public static SingleTon getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new SingleTon();
        }
        return uniqueInstance;
    }
}

设计思路是:

  1. 声明一个静态变量uniqueInstance,用来存放将实例化的对象;
  2. 将构造器声明为private,这样实例化只能在由类本身发起;
  3. 提供一个静态工厂方法getInstance,所有外部类都只能通过这个方法进行实例化。在实例化时只要判断一下实例是否已经创建,如果没创建则实例化一个并赋值给uniqueInstance, 最后放回uniqueInstance即可。

注: 这个实现并未考虑多线程的问题,仍然存在多线程创建多个实例的可能性。解决方法有三种:1. 通过synchronize方法将工厂方法声明为同步操作;2. 声明静态变量时直接初始化;3. 利用volatile+synchronize关键字,使用双重锁检查机制解决。有兴趣的同学可以直接google具体实现和利弊点, 这里篇幅限制不展开了。

python中能否参考这个思路来实现呢?看如下代码:

class SingleTon(object):
    _instance = None

    @classmethod
    def get_instance(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = SingleTon()
        return cls._instance


if __name__ == '__main__':
    instance_a = SingleTon.get_instance()
    instance_b = SingleTon.get_instance()
    instance_c = SingleTon()
    instance_d = SingleTon()
    print(instance_a is instance_b)
    print(instance_c is instance_d)

这段代码的最终输出如下:

True
Flase

可以看到,使用类方法进行实例化时达到了目的;但是,由于 python中并没有访问权限控制机制(而是依赖良好的规范约束,全靠自觉),依然存在调用方直接进行实例化的可能性,从而破坏了单例的事实。

那么如何解决这个问题呢?

重写__new__方法实现

在解决这个问题前需要了解一下python的两个方法: __new____init__:

__new__:这是一个类方法,用于创建实例(只创建对象,不做初始化),并返回创建的实例对象。

__init__:这是一个实例方法,用来做实例初始化的。该方法总是传入一个self对象,而self对象就是__new__方法创建的。因此,__new__方法总是先于__init__被调用。

既然问题的关键就在于控制实例对象的创建,我们很自然的想到重写__new__方法来达到目的, 具体实现如下:

class SingleTon(object):
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance

if __name__ == '__main__':
    instance_a = SingleTon()
    instance_b = SingleTon()
    print(instance_a is instance_b)

得到输出:

True

元类实现

另外一种方法是利用元类(metaclass), 所谓元类就是用来创建类的类,也就是元类的实例是一个类,元类常见于ORM实现。我们知道函数其实也是一个对象,函数的调用实际上是调用了函数对象的__call__方法。

既然类是元类的一个实例,那么元类的__call__方法实际就是类实例化方法(会议一下obj=SomeClass()语法)。因此,我们还可以通过指定元类的__call__方法来达到这个目的,如下:

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]


class ConcreteClass(metaclass=Singleton):
    pass

if __name__ == '__main__':
    instance_a = ConcreteClass()
    instance_b = ConcreteClass()
    print(instance_a is instance_b)

得到结果依然是:

True

相关文章

网友评论

    本文标题:Python中单例模式的实现

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