what's the 单例模式

what's the 单例模式

  单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例

  对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。

实现单例模式4中方式

1.文件导入

  文件导入实现单例模式的方式,主要是在一个py文件中创建要单例的类,然后实例化该类,得到该类的对象。以后调用的时候用文件导入的方式导入该对象,直接用对象.方法,无论使用该对象多少次,都只有一个实例对象在运行,即实现单例模式。

参考:django的admin和自己写的stark的site

 

2.类的方式实现(加锁是为了支持多线程)

# # 单例模式:支持多线程情况

import time
import threading
class Singleton(object):
    #创建锁,为多线程
    _instance_lock = threading.Lock()

    def __init__(self):
        time.sleep(1)#模拟多线程阻塞

    @classmethod
    def instance(cls, *args, **kwargs):
        # 判断进程,若省略这步直接加锁的话会使得每个进程来时无论实例化与否都加锁才验证,会造成延迟
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:#为应对多线程加锁
                if not hasattr(Singleton, "_instance"):#判断线程
                    Singleton._instance = Singleton(*args, **kwargs)#实例化
        return Singleton._instance#得到单例对象


def task(arg):
    obj = Singleton.instance()
    print(obj)
    
#批量创建多线程
for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()
time.sleep(20)



#单进程
obj = Singleton.instance()
print(obj)
#该方式的弊端:使用时必须先说明以后用单例模式时得用obj = Singleton.instance()
#若公司有个小白进来用obj = Singleton()的话就不是单例了
View Code

  该方式的弊端:使用时必须先说明以后用单例模式时得用obj = Singleton.instance()若公司有个小白进来用obj = Singleton()的话就不是单例了

 

3.类中基于基于__new__方式实现 (加锁是为了支持多线程)

import time
import threading
class Singleton(object):
    #创建锁,为多线程
    _instance_lock = threading.Lock()

    def __init__(self):
        pass


    def __new__(cls, *args, **kwargs):
        #实例化时就判断
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:
                if not hasattr(Singleton, "_instance"):
                    Singleton._instance = object.__new__(cls, *args, **kwargs)
        return Singleton._instance

obj1 = Singleton()
obj2 = Singleton()
print(obj1,obj2)


def task(arg):
    obj = Singleton()
    print(obj)

for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()

# 比方式2的优点:想用实现单例模式直接用obj = Singleton()即可,再也不用担心小白乱来了
View Code

  与方式2相比的优点:想实现单例模式直接用obj = Singleton()即可,再也不用担心小白乱来了

 

4.基于metaclass的方式实现(加锁是为了支持多线程)

import threading

class SingletonType(type):
    _instance_lock = threading.Lock()
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with SingletonType._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
        return cls._instance

class Foo(metaclass=SingletonType):
    def __init__(self,name):
        self.name = name


obj1 = Foo('name')
obj2 = Foo('name')
print(obj1,obj2)

# 分析:Foo类是其元类的对象,在Foo类加括号时(实例化Foo类得到obj)首先执行其元类的__call__方法,
# 会判断该类是否有实例,若有的话不再创建,即完成单例模式
View Code

  分析:Foo类是其元类的对象,在Foo类加括号时(实例化Foo类得到obj)首先执行其元类的__call__方法,会判断该类是否有实例,若有的话不再创建,即完成单例模式

总结

  四种单例模式都有其一定的应用场景,都能支持多线程的情况,文件导入的形式无需加锁。一般情况下用文件导入和__new__方式实现的情况较多,在源码中基于metaclass的方式实现较少。

原文地址:https://www.cnblogs.com/zhuminghui/p/8418978.html