单例模式(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查看
@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不能展示故贴图
代码实现
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 而言,小白的我,还是学习了很多知识点。
-
metaclass (
__metaclass__
)
metaclass 可以指定某个类的元类,何为元类?就是创建类的类。 - 存在意义:拦截类的创建、修改类、返回修改之后的类。 - 回到我们的单例模式,就是利用元类来实现的,Singleton 类就是 File 类的元类,可以理解为是 Singleton 创建了 File 类,(注意是类而不是类的实例)。具体就是调用了__new__
方法。-
__metaclass__
是实现自定义元类的一种方式,不多解释,有兴趣的可以参考如下两边文章,说的比较好,而且有 metaclass 更好的应用场景介绍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 方法。
sleep 函数是为了模拟线程间切换,如果不切换高概率是不会出现创建两个不同的实例的情况。
下集预告:工厂模式
说给自己听,当是给自己学习的一个动力吧!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。