jasper的技术小窝

关注DevOps、运维监控、Python、Golang、开源、大数据、web开发、互联网

单例模式

作者:jasper | 分类:python | 标签:       | 阅读 1117 次 | 发布:2014-12-21 12:03 a.m.

首先来谈谈在设计模式里的单例模式,说到单例模式,我想到了之前有个同事说过,他认为单例模式不能算是一种设计模式,当时他解释的原因是单例不能用到架构层,也许他有自己的理解吧。

单例模式,即是一个类有且仅有一个实例,并且自行实例化向整个系统提供。

在java中的实现方式有两种:懒汉式和饿汉式,当然还有一些他们的变种,下面我就列一下实现方式好了,因为这些解释已经被一群java大神写烂了。

一、懒汉式:

public class Singleton{
 private static Singleton instance=null;
 public static Singleton getInstance(){
     if(instance==null){
         synchronized(Singleton.class){
     if(instance==null)
         instance=new Singleton();
     }
}
 return instance;
 }
 private Singleton(){
 }
}

二、饿汉式:

public static class Singleton{
private static final Singleton instance=new Singleton();
private Singleton(){
    //dosomething
 }
public static Singleton getInstance(){
     return instance;
  }
}

那么在python中怎么去实现呢,我这边整理了好几种实现方式,下面一一道来:

一、类懒汉式:

import threading

class Singleton(object):
    __instance = None

    __lock = threading.Lock() 

    def __init__(self):
        pass

    @staticmethod
    def getInstance():
        if not Singleton.__instance:
            Singleton.__lock.acquire()
            if not Singleton.__instance:
                Singleton.__instance = object.__new__(Singleton)
                object.__init__(Singleton.__instance)
            Singleton.__lock.release()

这个是从java中的懒汉式演变而来的,

  1. 禁用__init__方法,不能直接创建对象。
  2. __instance,单例对象私有化。
  3. @staticmethod,静态方法,通过类名直接调用。
  4. __lock,代码锁。
  5. 继承object类,通过调用object的__new__方法创建单例对象,然后调用object的__init__方法完整初始化。
  6. 双重检查加锁,既可实现线程安全,又使性能不受很大影响。

但是,我是没有找到禁用__init__的方法,因为python中没有像java中有private来限制构造函数,所以导致s = Singleton()s2 = Singleton.getInstance()会是两个不同的对象,如果哪位大神有找到方法,麻烦告诉我一下。

二、装饰器:

def singleton(cls):
    instances = {}
    def _singleton(*args, **kw):
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]
    return _singleton

@singleton
class Singleton(object):
    def __init__(self):
        pass

singleton这是一个单例类的装饰器,思想就是把实现放在一个dict中,如果已经创建过就直接返回,如果没有就创建后再返回,注意网上有些不太准确的例子,就是用装饰器的单例时,实例化时不能传参,希望大家注意一下。

三、重写new方法:

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

其实python中创建对象的时候就是调用的new方法,所以通过对其的重写,来限制对象的创建。

四、使用元类:

class SingletonMeta(type):  
    def __init__(cls, name, bases, dict):  
        super(SingletonMeta, cls).__init__(name, bases, dict)  
        cls._instance = None  
    def __call__(cls, *args, **kw):  
        if cls._instance is None:  
            cls._instance = super(SingletonMeta, cls).__call__(*args, **kw)  
        return cls._instance  

class Singleton(object):  
    __metaclass__ = SingletonMeta

其实这个是方法三的高级用法,调用call时,会返回这个实例。

五、共享属性:

class Share(object):  
    _state = {}  
    def __new__(cls, *args, **kw):  
        ob = super(Share, cls).__new__(cls, *args, **kw)  
        ob.__dict__ = cls._state  
        return ob  

class Singleton(Share):  
    pass

这种方式保证了所有引用(实例、对象)拥有相同的状态(属性)和行为(方法) ,因为他们的__dict__是一样的,但是他们并不是同一个对象,通过查看各自的id就可以知道,但并不妨碍我们可以把它当做单例来用。

python的单例实现方式大体就这么几种,如果大家还发现有什么方式,希望能告知。

最后我想说的是,虽然我们可以用各种各样的方法实现python中的单例模式,但是实际上在python中不必要去刻意实现的,因为作为一个静态语言,它的每一个模块都可以看作是单例的。怎么说,举个最常用的例子,在django中,我们一般会把一些外部数据的连接直接实现,而放在settings.py中,比如对mongo的连接啊什么的,这样在我们的程序中用的时候,就会一直是同一个连接,从而保证了单例。


转载请注明出处:http://www.opscoder.info/singleton.html

【上一篇】 设计模式在python中的应用
【下一篇】 工厂模式
其他分类: