python 设计模式(一) 单例模式

单例模式

单例模式:不管用类实例化对象多少次,所得到的对象都是同一个对象。这种模式的应用场景,如数据库连接,配置信息等。

1 通过类的嵌套实现单例

# create singleton by means of class nestification

class Singleton(object):
    # really working class
    class Wrapper_class(object):

        def __init__(self, name):
            self.name = name

        def show_id(self):
            return id(self)

        def work(self):
            print('i am working')

    # save Wrapper_class instance
    _instance = None

    def __init__(self):
        if Singleton._instance is None:
            Singleton._instance = Singleton.Wrapper_class('wrapper')
    # when get attribute if not exist, call this function. it return getattr function. 
    def __getattr__(self, item):
        return getattr(self._instance, item)
    # getattr include three params: instance name, attribute or method name, default value when instance not include attribute

if __name__ == '__main__':
    a = Singleton()
    b = Singleton()
    print(a)
    print(b)
    print(a.show_id())
    print(b.show_id())

以上代码修改自实验楼--python设计模式--单例。如有侵权请联系[email protected]

代码解析:Wrapper_class类是真正干活的类,它只进行一次实例化,并用Singleton类变量_instance保存,不管对Singleton类进行多少次实例化,内部由Wrapper_class类实例化出的干活的对象就只有一个。

Singleton类的方法__getattr__作用是:当调用了Singleton类不存在的方法或者属性时,就会运行Singleton的__getattr__方法。

return getattr(对象,属性或方法) 作用:检查属性或方法是否属于对象,属于的话,调用这个方法或者对象。

本例中,调用了Singleton类实例化对象的show_id()方法,但Singleton类中并未实现这个方法,因此首先调用了Singleton类的__getattr__方法,并返回了getattr(self._instance, item)方法,这个方法首先检查Wrapper_class类实例化的保存在_instance中的对象是否具有show_id()方法,正好Wrapper_class类中实现了这个方法,因此运行了这个方法,得到了结果

<__main__.Singleton object at 0x000002346197C358>
<__main__.Singleton object at 0x000002346197C550>
2423998891120
2423998891120
由结果知,不管实例化多少次Singleton类,但最终干活的对象都是同一个

2 装饰器实现单例

利用类装饰器实现单例

先上代码吧

# create singleton by means of class decorator
class Decorator(object):

    def __init__(self, cls):
        self._cls = cls

    def __call__(self, *args, **kwargs):
        try:
            return self._instance
        except AttributeError:
            self._instance = self._cls()
            return self._instance


@Decorator
class Work(object):

    def __init__(self):
        pass

    def show_id(self):
        return id(self)


if __name__ == '__main__':
    a = Work()
    b = Work()
    print(a.show_id())
    print(b.show_id())

结果为

1969722475520
1969722475520

上述代码中,类Decorator是装饰器类,其override了__call___方法,进行了custom。__call__方法使类Decorator实例化的对象可以像函数一样被调用。因此可以当做装饰器装饰其他函数或类。只有可调用对象才能作为装饰器

对于用函数去装饰函数这样的简单的装饰器类型,很容易理解其中代码的执行流程。但理解类装饰类这种类型确实让我头疼。就比葫芦画瓢地理解吧。函数装饰函数类型:装饰后返回的是装饰器内层的函数,然后替代原来的函数。那么同理,用类去装饰类,装饰后返回的应该是装饰器中的类的实例(别打脸,我猜的)。先就这样理解吧。正如上面的例子。类Work被类Decorator装饰,那么装饰后类Work就被传递进了Decorator的self._cls位置。然后把类Decorator的实例返回,并代替类Work的位置。当调用类Work进行实例化时,实际上调用的是装饰过以后的类Decorator的实例。仔细观察类Decorator的代码,可知,首次创建的时候,会生成一个实例属性self._instance。当第二次进行调用的时候,直接返回的是self._instance。因此就实现了单例模式。我对这段代码还是有很多疑惑。真正懂的大神可以评论告诉我啊,小弟在这里先谢过,有人说,这段代码不能用于多线程,我没试过,大家注意下

3 通过__new__方法实现单例

# crate singleton by means of __new__
class Singleton(object):
    _instance = None # 一个下划线开头表示受保护的属性

    # __new__函数在调用__init__方法前调用,目的是创建一个对象,因此,其方法的第一个参数要传递类名,cls,而不是self
    # 只有创建了对象后才能使用self
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance
    
if __name__ == '__main__':

    a = Singleton()
    b = Singleton()
    print(id(a), id(b))

结果为

2025743751544 2025743751544

总结:

    以上通过三种方法实现了单例模式,但实际项目中,也可以不使用单例模式,而只在初始化时,创建一个实例,其他模块共用这个实例,这同样能实现单例的效果。




猜你喜欢

转载自blog.csdn.net/ruguowoshiyu/article/details/80599842