• 🍖单例模式


    一. 什么是单例模式

    单例模式 (Singleton Pattern) 是一种常用的软件设计模式 (Deaign pattern), 提供了在软件开发过程中面临的一些问题的最佳解决方案

    而单例模式的主要目的是确保某一个类只有一个实例存在, 即一个类多次实例的结果指向同一个对象, 用于节省内存

    如果我们从配置文件中读取配置来进行实例化, 在配置相同的情况下, 就没有必要重复产生对象来浪费内存了

    二.单例模式的优缺点

    1.单例模式的优点

    • 由于单例模式要求在全局类只有一个实例, 因而可以节省比较多的内存空间
    • 全局只有一个接入点, 可以进行更好的进行数据同步控制, 避免多重占用
    • 单例可以常驻内存, 减少内存开销

    2.单例模式的缺点

    • 单例模式的扩展比较困难
    • 赋于了单例以太多的职责,某种程度上违反单一职责原则
    • 单例模式是并发协作软件模块中需要最先完成的,因而其不利于测试
    • 单例模式在某种情况下会导致 "资源瓶颈"

    三.单例模式的应用场景示例

    • 生成全局惟一的序列号
    • 访问全局复用的惟一资源,如磁盘、总线等
    • 单个对象占用的资源过多,如数据库等
    • 系统全局统一管理,如Windows下的Task Manager
    • 网站计数器

    四.实现单例模式的五种常用方式

    1.使用模块导入

    前面我们介绍过模块导入只有首次导入会执行模块文件, 后面的导入都是直接使用第一次导入的结果, 因为在模块第一次导入时会生成一个 .pyc 文件, 后面导入直接加载它, 既然如此, 那么 Python 的模块就是一个天然的单例模式

    • test.py 文件内容
    class Singletan:
        NAME = "北极星"
        PASSWD = "275242996"
        AGE = 22
        SEX = "man"
    
    info = Singletan()
    
    • 执行文件正确演示
    from test import info  # 第一次导入执行test文件生成 .pyc 文件
    from test import info  # 第二次导入直接加载 .pyc 文件
    
    obj1 = info
    obj2 = info
    
    print(obj1 is obj2)  # True
    
    • 执行文件错误演示
    from test import Singletan  # 第一次导入执行test文件生成 .pyc 文件
    from test import Singletan  # 第二次导入直接加载 .pyc 文件
    
    info1 = Singletan()
    info2 = Singletan()
    
    print(info1 is info2)  # False
    

    2.使用类装饰器来实现

    def Singletan(cls):
        __instance = None        # 定义一个常量, 用来存对象, 以后每次都返回这个对象
        def wrapper(*args,**kwargs):
            nonlocal __instance  # 声明内层的"__instance"是外层函数的变量,不声明报错
            if not __instance:   # 对象不存在,将类的实例赋值给"__instance"
                __instance = cls(*args,**kwargs)  
                # 这里是进行赋值操作,但如果没有声明成外层函数变量, 机器会识别成你是在定义变量,在定义之前引用会报错
            return __instance    # 对象已经存在时直接将对象返回
        return wrapper
    
    @Singletan  # Singletan(Info)---->返回wrapper = Info
    class Info:
        def __init__(self):
            ...
    
    obj1 = Info()
    obj2 = Info()
    
    print(obj1 is obj2)  # True
    

    3.使用类的绑定方法实现

    class Singletan:
        __instance = None                    # 设置变量存放对象
        NAME = "shawn"
        PASSWD = "275242996"
    
        @classmethod
        def get_obj(cls):
            if not Singletan.__instance:     # 判断是否对象存在
                Singletan.__instance = cls() # 不存在实例出一个赋值
            return Singletan.__instance      # 存在直接返回这个对象
    
    obj1 = Singletan.get_obj()
    obj2 = Singletan.get_obj()
    
    print(obj1 is obj2)  # True
    
    • 当使用了类的绑定方法实现单例后, 正常实例出来的对象不是单例
    obj3 = Singletan()
    obj4 = Singletan()
    
    print(obj3 is obj4)  # False
    

    4.基于 __new__ 方法实现单例

    class Singletan:
        __instance = None                   # 设置变量存放对象
        NAME = "shawn"
        AGE = 22
    
        def __new__(cls, *args, **kwargs):
            if not cls.__instance:         # 判断是否对象存在
                cls.__instance = super().__new__(cls)  # 不存在就实例出一个并赋值
            return cls.__instance          # 存在直接返回这个对象
    
    obj1 = Singletan()
    obj2 = Singletan()
    
    print(obj1 is obj2)  # True
    

    5.通过元类实现

    class SingletanType(type):
        __instance = None      # 设置变量存放对象,Singletan中找不到会跑这来找      
    
        def __call__(self, *args, **kwargs):
            if not self.__instance:    # 判断是否对象存在
                self.__instance = self.__new__(self)  # 不存在就实例出一个并赋值
                # SingletanType.__instance = self.__new__(self) 直接设置元类的属性,类中找不到会到元类找(了解)
            return self.__instance     # 存在直接返回这个对象
    
    class Singletan(metaclass=SingletanType):
        NAME = "shawn"
        AGE = 22
    
    obj1 = Singletan()  # 触发元类的 __call__
    obj2 = Singletan()
    
    print(obj1 is obj2)  # True
    
  • 相关阅读:
    Lodash 严重安全漏洞背后 你不得不知道的 JavaScript 知识
    SQL Server和C#中无法将小数字符串直接转换为整数类型
    Is default(CancellationToken) equivalent to CancellationToken.None?(转载)
    Stored Procedures: OUTPUT vs OUT?(转载)
    关于TransactionScope.Complete方法(链接)
    Do I need to dispose of Tasks?(链接)
    EF Core 3.0 Keyless Entity Types (链接)
    为什么C#接口中不能声明async异步函数(转载)
    How does SqlDataReader handle really large queries?(转载)
    ASP.NET Core MVC中的Filter如果不实现IFilterFactory接口,那么Filter默认情况下在ASP.NET Core生命周期内是单例的,会被重用
  • 原文地址:https://www.cnblogs.com/songhaixing/p/14247144.html
Copyright © 2020-2023  润新知