Neil啃设计模式(0x01)单例模式

单例模式(Singleton Pattern)

“单例模式(Singleton Pattern)是一个比较简单的模式,其定义以下:
Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,并且自行实例化并向整个系统提供这个实例。)”
Excerpt From: 秦小波 著. “设计模式之禅(第 2 版)(华章原创精品).” iBooks.

定义

UML 示例

能够经过plantuml查看html

@startuml
class Singleton{
   + name
}
note top:Singleton has a 'name' property.此处的Singleton表明下边代码中的File类

class Client
note left: client get one singleton instance
Client --> Singleton
@enduml

因为此markdown不能展现故贴图
image.pngjava

代码实现

import threading
import time


class Singleton(type):
    def __new__(cls, *args, **kwargs):
        return type.__new__(cls, *args, **kwargs)

    def __init__(self, *agrs, **kwargs):
        self.__instance = None
        super().__init__(*agrs, **kwargs)

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            # time.sleep(2) 模拟线程切换,此时不能保证多线程单例实现
            self.__instance = super().__call__(*args, **kwargs)
            return self.__instance
        else:
            return self.__instance


class File(metaclass=Singleton):
    def __init__(self, name):
        self.name = name


def create_file_instance(name):
    f = File(name)
    print(f)


# if __name__ == "__main__":
#     thread1 = threading.Thread(target=create_file_instance, args=('abc', ))
#     thread2 = threading.Thread(target=create_file_instance, args=('bcd', ))

#     thread1.start()
#     thread2.start()
# 若是有sleep会出现此状况:
#<__main__.File object at 0x1052d34a8>
#<__main__.File object at 0x1052d3390>
# 若是没有高几率不会出现不一致的状况,由于代码消耗的cpu时间很短,不足以形成线程切换
# -------------------多线程下单例实现---------------- #


def synchronized(func):
    func.__lock__ = threading.Lock()

    def lock_func(*args, **kwargs):
        with func.__lock__:
            return func(*args, **kwargs)

    return lock_func


class SingletonSync(type):
    def __init__(self, *agrs, **kwargs):
        self.__instance = None
        super().__init__(*agrs, **kwargs)

    @synchronized
    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            time.sleep(2)
            self.__instance = super().__call__(*args, **kwargs)
            return self.__instance
        else:
            return self.__instance


class FileSync(metaclass=SingletonSync):
    def __init__(self, name):
        self.name = name


def create_file_instance_sync(name):
    f = FileSync(name)
    print(f)


if __name__ == "__main__":
    thread1 = threading.Thread(target=create_file_instance_sync, args=('abc', ))
    thread2 = threading.Thread(target=create_file_instance_sync, args=('bcd', ))

    thread1.start()
    thread2.start()
#<__main__.FileSync object at 0x10fbd43c8>
#<__main__.FileSync object at 0x10fbd43c8>
参考代码:Python Cookbook - 9.13.2 章节
同步锁机制: https://blog.csdn.net/lucky40...

知识点

学习《设计模式之禅》这本书,但又没有使用 java 语言,便突发奇想,结合设计模式的书,参考 python 的相关书籍编写 python 的设计模式的例子。相对于 java 来讲单例应该是设计模式中最好理解和最好编写的代码了,可是对于 python 而言,小白的我,仍是学习了不少知识点。python

  • metaclass ( __metaclass__ )
    metaclass 能够指定某个类的元类,何为元类?就是建立类的类。 - 存在乎义:拦截类的建立、修改类、返回修改以后的类。 - 回到咱们的单例模式,就是利用元类来实现的,Singleton 类就是 File 类的元类,能够理解为是 Singleton 建立了 File 类,(注意是类而不是类的实例)。具体就是调用了__new__方法。设计模式

    • __metaclass__是实现自定义元类的一种方式,很少解释,有兴趣的能够参考以下两边文章,说的比较好,并且有 metaclass 更好的应用场景介绍markdown

      https://www.cnblogs.com/Simon... https://www.liaoxuefeng.com/wiki/1016959663602400/1017592449371072
  • __new__ 方法:很是基础的知识点,newe 函数是执行 init 以前执行的函数,真正建立类的是 new 函数,new 函数会逐级查找__metaclass__(元类方法),若是找到就执行,找不到就继续查找父类,若是都没有最终会调到 type,type 也是一个元类,并且是像 int、string 等的元类,就是 type 建立了 int、string
  • __call__ 方法:File()执行的时候被调度的函数。全部定义了 call 方法的类均可以被称为是可执行的,就是能够当成一个函数执行。

说了这几个知识点,若是不太懂元类,或者 call 方法,可能仍是不太好理解这个单例的执行,一个简单地方式就是回去跑一下试试。
说一下代码执行流程(只介绍 File 建立的流程):多线程

在 File()执行以前,在 File 被定义传来的时候 Singleton 的 new 函数就被执行了,目的就是为了建立出这个 File 类,这也是为何会写上 new 函数的缘由,其实不写不会影响单例模式,而后 Singleton 的 init 被执行,目的是为了建立 instance 实例,实例名称也有讲究,双下划线表示隐私属性不会被复写。接着,当 File 函数被执行时会调用 call 方法。ide

sleep 函数是为了模拟线程间切换,若是不切换高几率是不会出现建立两个不一样的实例的状况。函数

下集预告:工厂模式

说给本身听,当是给本身学习的一个动力吧!学习

相关文章
相关标签/搜索