设计模式:单例(Singleton Pattern)

使用场景

单例确保一个类只有一个实例存在。比如在服务器的配置信息存放一个文件,客户端通过一个 AppConfig 的类来读取配置文件的信息,如果在程序运行期间,很多地方都需要使用配置文件的内容,也就是说很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,会浪费内存。这时就应该使用单例,确保只有一个实例。

Python 实现单例

  1. 使用模块
  2. 使用 new
  3. 使用装饰器
  4. 使用元类

使用模块

原理:Python 的模块就是天然的单例。模块第一次导入时会生成 .pyc,第二次导入就会直接加载 .pyc,不会执行模块代码。

# singleton.py
class Singleton:
  def foo(self):
      pass
# 注意这行
my_singleton = Singleton()

调用

from singleton import my_singleton
my_singleton.foo()

使用 __new__

# __new__ 是拦截器,会在 __init__ 之前被调用
class Singleton:
    _instance = None

    def __new__(cls, *args, **kw):
        if not cls._instance:
            # cls._instance = object.__new__(cls, *args, **kw)
            cls._instance = super().__new__(cls, *args, **kw)
        return cls._instance


if __name__ == '__main__':
    s = Singleton()
    print(s)

使用装饰器

from functools import wraps


def single_dec(cls):
    _instance = {}
    
    @wraps(cls)
    def get_instance(*args, **kwargs):
        if cls not in _instance:
            _instance[cls] = cls()
        return _instance[cls]
    return get_instance


@single_dec
class Single:
    pass 


if __name__ == '__main__':
    s = Single()

使用元类

注意使用元类和使用 __new__ 的不同。

class Singleton(type):
    _instance = None

    def __call__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__call__(*args, **kwargs)
        return cls._instance


class SingleIns(metaclass=Singleton):
    pass


if __name__ == '__main__':
    s = SingleIns()
    ss = SingleIns()
    print(id(s), id(ss))

Java 中使用单例

class Soup2{
  private Soup2(){}
  private static Soup2 ps1 = new Soup2();
  public static Soup2 access(){
      return ps1;
  }
  public void f() {}
}

把构造器声明为 private 可以阻止直接创建某个类的实例;

如果没有创建构造器的话,编译器会默认创建一个不带任何参数的构造器。

所以,为了阻止编译器创建默认的构造器,需要手动创建一个构造器。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,390评论 19 139
  • 〇、前言 本文共108张图,流量党请慎重! 历时1个半月,我把自己学习Python基础知识的框架详细梳理了一遍。 ...
    Raxxie阅读 19,235评论 17 410
  • 1 场景问题# 1.1 读取配置文件的内容## 考虑这样一个应用,读取配置文件的内容。 很多应用项目,都有与应用相...
    七寸知架构阅读 11,775评论 12 68
  • 对销售人员,我一直是用一种崇拜的眼光看待,我觉得推销一样东西,让别人接受是很困难的事情。这次加入果语,并不断升级的...
    绽蕊向阳阅读 3,382评论 0 0
  • 静谧的夜,窗帘遮去了晚来的风。 电话响起。响得不合情理。 “喂,请问是68757398吗?” “是的,是68757...
    强哥_2018阅读 2,720评论 1 2