[python实现设计模式]-1. 单例模式

设计模式中,最简单的一个就是 “单例模式”, 那么首先,就实现一下单例模式。html

那么根据我的的理解,很快就写出初版。java

# -*- coding: utf-8 -*-


class Singleton(object):

    # 定义静态变量实例
    __singleton = None

    def __init__(self):
        pass

    @staticmethod
    def get_instance():
        if Singleton.__singleton is None:
            Singleton.__singleton = Singleton()
        return Singleton.__singleton

测试一下:python

 

if __name__ == "__main__":
    instance1 = Singleton.get_instance()
    instance2 = Singleton.get_instance()

    print id(instance1)
    print id(instance2)



liutrumpdeMacBook-Air:singleton trump$ python Singleton
4419778640
4419778640c#

看起来运行良好。可是其实,这里面有2个问题.设计模式

 

1. 这里类方法getinstance()用于获取单例,可是类自己也能够实例化,这样的方式其实并不符合单例模式的要求。安全

 

if __name__ == "__main__":
    instance1 = Singleton.get_instance()
    instance2 = Singleton.get_instance()

    instance3 = Singleton()

    print id(instance1)
    print id(instance2)
    print id(instance3)

执行结果:
liutrumpdeMacBook-Air:singleton trump$ python Singleton 
4461824080
4461824080
4461824144

在c#或java的设计模式中,咱们一般是经过私有化类的构造函数来杀死类自己的繁殖能力多线程

然而python并无访问限定强制约束, 那么怎么办呢?函数

这个后续再说.性能

可是这样作也有好处,代码简单,你们约定好这样子调用就好了。测试

可是最好在类的命名上也体现了出来这是一个单例类.

 

2. 这个单例类并非线程安全的.

好比我写了以下的测试代码来测试它的线程安全性.

def test_singleton_in_thread():
    print id(Singleton.get_instance())

if __name__ == "__main__":
    idx = 0
    while 1:
        MyThread(test_singleton_in_thread, []).start()
        idx += 1
        if idx > 0X100:
            break

很快,就发现这确实不是线程安全的....

 

 关于问题1. 咱们换个思路, 来谈一谈python里面的构造函数.(其实python里面并无构造函数个概念,⊙﹏⊙, 叫习惯了而已)

 python 里的__init__(self) 函数,以前一直被我认为是python类的构造函数 __del__(self), 一直被我认为是类的析构函数...

其实,这是不对滴.

这时候__new__(self)就要登场了.

咱们看一下官方的介绍.

http://docs.python.org/2/reference/datamodel.html#object.new

 

这么鬼长,其实告诉咱们了一个道理.

new是一个类方法,会建立对象时调用。而init方法是在建立完对象后调用,对当前对象的实例作一些一些初始化,无返回值。若是重写了new而在new里面没有调用init或者没有返回实例,那么init将不起做用。

我擦,类方法,又是什么鬼....

好吧,继续查下资料.

http://www.cnblogs.com/2gua/archive/2012/09/03/2668125.html

静态方法:没法访问类属性、实例属性,至关于一个相对独立的方法,跟类其实没什么关系,换个角度来说,其实就是放在一个类的做用域里的函数而已。

类成员方法:能够访问类属性,没法访问实例属性。
类方法有类变量cls传入,从而能够用cls作一些相关的处理。而且有子类继承时,调用该类方法时,传入的类变量cls是子类,而非父类。 
 
了解了这些姿式之后,咱们能够尝试经过改造类的__new__方法来给类进行计划生育了.
 

尝试了写了一下.

然而报一个递归溢出......

 

查了一下. 借鉴了一下

http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python/31887#31887

# -*- coding: utf-8 -*-


class Singleton(object):

    # 定义静态变量实例
    __instance = None

    def __init__(self):
        pass

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

if __name__ == "__main__":
    instance1 = Singleton()
    instance2 = Singleton()

    print id(instance1)
    print id(instance2)

liutrumpdeMacBook-Air:singleton trump$ python Singleton3.py
4544985488
4544985488

 

这里不是很懂super的用法. 查了一下文档.

 

 看起来是调用了object类的 __new__方法来构造出了咱们须要的类.(相似于c#里的反射???,不知道python的解释器是如何实现的)

 

总之看起来是靠谱的。耶耶耶。

一样的, 这种写法依然不是线程安全的.

 

关于问题2.

 

为了保证在多线程下线程安全性。 

咱们在写单例模式时候, 一般使用双重检查锁定来检测实例是否存在。

为何用double check, 请自行思考...

实现: 

# -*- coding: utf-8 -*-
from MyThread import *
import threading

Lock = threading.Lock()


class Singleton(object):

    # 定义静态变量实例
    __instance = None

    def __init__(self):
        pass

    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            try:
                Lock.acquire()
                # double check
                if not cls.__instance:
                    cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
            finally:
                Lock.release()
        return cls.__instance


def test_singleton_in_thread():
    print id(Singleton())

if __name__ == "__main__":
    idx = 0
    while 1:
        MyThread(test_singleton_in_thread, []).start()
        idx += 1
        if idx > 0X100:
            break

 

运行结果: 

证实是线程安全的. 欧耶.

 

上面的代码在单例模式中被称做,懒汉式单例.

还有一种称之为饿汉式单例.

遗憾的是,python下是没有办法实现的。

饿汉,太饿了, 一开始就把实例构造出来...是否是很形象.

 

贴个c#的代码,供参考.

解释: 声明一个私有static 成员实例并直接调用类默认静态构造函数实例化.

而后安插共有静态方法返回该实例.

使用CLR的静态成员只能在静态构造函数中构造而且只能构造一次的特性来实现了单例.

特别的直观和美观, 也保证了线程安全.

使用起来很方便.

但也有个弊端就是须要在类加载的时候就把实例给初始化出来.

当这个实例很是大或者构造很耗时的话此时的性能就会有影响.

 一般状况,这种写法是使用最多的写法(反正我写的话确定不想使用double check...)

class Singleton   
{   
    private static Singleton instance = new EagerSingleton();   
  
    private Singleton() { }   
  
    public static Singleton GetInstance()   
    {  
        return instance;   
    }  
} 

 

 

 

总结: 

本文介绍了使用python来实现不能约束构造实例只能经过规约指定方法来实现的单例模式,并由此引伸控制类的__new__函数来

约束类构造的实例。

本文而且讨论了多线程下的double check 的单例模式的实现。

本文而且讨论了单例模式的懒汉式实现以及饿汉式实现.

 

 

好,第一个最简单的设计模式的python实现就到这里。

to be continued.

相关文章
相关标签/搜索