当前位置:首页 > 科技  > 软件

三言两语说透设计模式的艺术-单例模式

来源: 责编: 时间:2023-08-05 11:44:51 5798观看
导读写在前面单例模式是一种常用的软件设计模式,它所创建的对象只有一个实例,且该实例易于被外界访问。单例对象由于只有一个实例,所以它可以方便地被系统中的其他对象共享,从而减少系统中的资源开销。单例模式单例模式的实现

写在前面

单例模式是一种常用的软件设计模式,它所创建的对象只有一个实例,且该实例易于被外界访问。单例对象由于只有一个实例,所以它可以方便地被系统中的其他对象共享,从而减少系统中的资源开销。Jnc28资讯网——每日最新资讯28at.com

单例模式

单例模式的实现思路是:Jnc28资讯网——每日最新资讯28at.com

  1. 构造函数需要被私有化,外部无法直接通过new来创建对象实例。
  2. 提供一个静态的公有访问点,用于获取单例对象的实例。
  3. 通过判断实例是否已经存在来决定创建或直接返回现有实例。

单例模式的要点:Jnc28资讯网——每日最新资讯28at.com

  • 某个类只能有一个实例
  • 它必须自行创建实例
  • 它必须自行向整个系统提供整个实例

我们来看一下使用TypeScript实现单例模式的代码示例:Jnc28资讯网——每日最新资讯28at.com

class Singleton {  // 私有静态属性,存储唯一实例  private static instance: Singleton;  // 私有构造函数,防止外部实例化  private constructor() {}  // 向外部提供能够共享访问的唯一实例  public static getInstance(): Singleton {    if (!Singleton.instance) {      Singleton.instance = new Singleton();    }    return Singleton.instance;  }  // 其他方法和属性}const s1 = Singleton.getInstance(); const s2 = Singleton.getInstance();console.log(s1 === s2); // true

上面代码中,Singleton类的构造函数被private修饰,使其无法在类的外部通过new来创建实例。Jnc28资讯网——每日最新资讯28at.com

getInstance方法首先会判断实例是否存在,如果不存在才去新建实例,如果实例已存在则直接返回现有实例。这确保了整个程序中只会创建该类的一个实例。Jnc28资讯网——每日最新资讯28at.com

测试代码中,s1和s2实际上是获取的是同一个实例对象。Jnc28资讯网——每日最新资讯28at.com

图片图片Jnc28资讯网——每日最新资讯28at.com

单例模式的优点:Jnc28资讯网——每日最新资讯28at.com

  • 对唯一实例的受控访问。
  • 由于单例对象存放在静态变量中,所以可以直接通过类名访问,简单方便。
  • 可以避免对资源的重复占用。

单例模式的缺点:Jnc28资讯网——每日最新资讯28at.com

  • 没有抽象层,扩展困难。
  • 单例类的职责过重,违反单一职责原则。
  • 没有接口,依赖具体实现,导致扩展性差。

Singleton单例:在单例类的内部实现只生成一个实例,同时提供一个静态方法getInstance()方法,让用户可以访问它的唯一实例;为了防止在外部对单例类实例化,它的构造函数可见性为private;在单例类内部定义了一个Singleton类型的静态属性instance,作为提供给外部共享访问的唯一实例。Jnc28资讯网——每日最新资讯28at.com

饿汉式单例类

饿汉式单例类:当类被加载时,静态属性instance会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将会被创建。Jnc28资讯网——每日最新资讯28at.com

普通单例模式和饿汉式单例模式的区别:Jnc28资讯网——每日最新资讯28at.com

  • 普通单例模式是在第一次调用getInstance方法时才创建实例对象。
  • 饿汉式是无论是否调用都会在类加载时就创建实例对象。

下面我们使用TypeScript代码实现一个饿汉式单例:Jnc28资讯网——每日最新资讯28at.com

class Singleton {  private static instance = new Singleton();    private constructor() {}  public static getInstance() {    return Singleton.instance;  }}const s1 = Singleton.getInstance();const s2 = Singleton.getInstance(); console.log(s1 === s2); // true

饿汉式单例由于在类加载时就完成了初始化,所以理论上它是线程安全的,在多线程环境下也能保证单例。Jnc28资讯网——每日最新资讯28at.com

但饿汉式也有可能造成不必要的实例化,如果这个单例的实例对象较大,而客户端又没调用getInstance方法,那就会浪费内存。Jnc28资讯网——每日最新资讯28at.com

懒汉式单例模式

其实懒汉式单例模式,就是前面提到的普通单例模式。Jnc28资讯网——每日最新资讯28at.com

懒汉式单例模式实现代码如下:Jnc28资讯网——每日最新资讯28at.com

class Singleton {  private static instance: Singleton;  private constructor() {}  public static getInstance(): Singleton {    if (!Singleton.instance) {      Singleton.instance = new Singleton();    }    return Singleton.instance;   }}

但是,这种实现方式存在一个问题,就是在多线程环境下会存在安全隐患。Jnc28资讯网——每日最新资讯28at.com

如果有两个线程A和B,它们同时调用 getInstance 方法,并且实例还没有被初始化,那么它们会同时执行 Singleton.instance = new Singleton();这行代码。Jnc28资讯网——每日最新资讯28at.com

这样就会导致实际创建了两个实例,违反了单例模式的初衷。Jnc28资讯网——每日最新资讯28at.com

为了使懒汉式单例在多线程中也是安全的,我们可以对getInstance方法加锁:Jnc28资讯网——每日最新资讯28at.com

class Singleton {  private static instance: Singleton;  private constructor() {}  public static getInstance(): Singleton {    if (!Singleton.instance) {      // 加锁      lock()        if (!Singleton.instance) {        Singleton.instance = new Singleton();      }      // 释放锁       unlock()    }    return Singleton.instance;  }}

这样当一个线程进入该方法时,其它线程就只能等待,直到锁被释放后才能进入方法。Jnc28资讯网——每日最新资讯28at.com

这就确保了单例实例的唯一性。这里的锁机制可以使用互斥量mutex等各种锁的实现。Jnc28资讯网——每日最新资讯28at.com

以上是关于懒汉式单例线程安全性问题的一个补充说明。让我们的单例模式实现更加健壮。Jnc28资讯网——每日最新资讯28at.com

饿汉式单例与懒汉式单例类比较

  1. 实例化时机不同
  • 懒汉式是在第一次调用getInstance时才实例化Singleton对象
  • 饿汉式是在类加载时就实例化了Singleton对象
  1. 资源利用效率不同
  • 懒汉式更节约资源,按需实例化,如果一直没有调用getInstance也不会实例化
  • 饿汉式不管是否需要都会实例化,如果长时间没有使用就会浪费内存
  1. 多线程安全性不同
  • 饿汉式天然是多线程安全的,因为实例在类加载时就已经创建好了
  • 懒汉式需要额外的同步机制来保证多线程安全
  1. 使用场景不同
  • 懒汉式更适合实例化过程比较耗时或耗资源的情况
  • 饿汉式更适合实例化过程很快且确定会用到的情况

懒汉式相比饿汉式更加灵活,但需要处理多线程安全问题。饿汉式编写简单但不太高效。Jnc28资讯网——每日最新资讯28at.com

在实际开发中,我们可以根据需求选择合适的实现方式,也可以采用双重校验锁等线程安全的懒汉式实现。Jnc28资讯网——每日最新资讯28at.com

一种更好的单例实现方式

饿汉式单例类不能实现延迟加载,不管将来用不用,它始终占据内存;懒汉式单例类线程安全控制繁琐,而且性能收到影响。对此,无论是饿汉式单例还是懒汉式单例都在一些问题,使用IoDH(Initialization on Demand Holder)可以结合两者的优点,克服两者的缺点实现性能和实现更优的单例模式。Jnc28资讯网——每日最新资讯28at.com

IoDH是一种技术方案,它利用了类的静态属性来实现延迟加载和线程安全。要实现IoDH,只需在但李磊中增加静态内部类即可,在该内部类中创建单例对象,再将该单例对象通过getInstance()方法返回给外部使用。Jnc28资讯网——每日最新资讯28at.com

// 单例服务接口interface SingletonService {  doSomething(): void; }// 单例服务类class SingletonServiceImpl implements SingletonService {  doSomething() {    console.log('Doing something...');  }}// IoC容器类class IoCContainer {  private singleton: SingletonService;  constructor() {    this.singleton = new SingletonServiceImpl();  }  getSingleton(): SingletonService {    return this.singleton;  }}// 测试代码const container = new IoCContainer();const s1 = container.getSingleton();const s2 = container.getSingleton();console.log(s1 === s2); // true

详细解析一下使用IoC容器实现单例模式的代码:Jnc28资讯网——每日最新资讯28at.com

  1. 定义了单例服务接口SingletonService,用于规范单例对象的操作。
  2. SingletonServiceImpl实现了该接口,作为单例对象的具体实现类。
  3. IoC容器类IoCContainer在内部持有SingletonService类型的成员变量singleton。
  4. IoC容器类的构造函数中会实例化这个singleton对象,确保全局只有这一个实例。
  5. getSingleton()方法用来返回这个singleton实例。
  6. 在测试代码中,从IoC容器中获取了两次单例对象,并比较它们的引用是否相同。
  7. 运行结果证明两次获取的确是同一个对象引用,即单例。

这样通过IoC容器管理单例的创建,可以实现:Jnc28资讯网——每日最新资讯28at.com

  1. 把单例对象的创建和生命周期管理转移到IoC容器。
  2. 外部代码不需要关心单例内部的具体实现,只需要从容器中获取实例即可。
  3. 符合单一职责原则,程序逻辑更清晰。
  4. 有利于代码的可测试性,可以通过mock容器进行单元测试。
  5. 扩展性较好,如果要切换不同的单例实现,只需要调整容器中的对象创建即可。

总结

单例模式作为一种设计模式,由于具有明确的目的、简单的结构和易于理解的特点,在软件开发中使用频率很高,在许多应用程序和框架中都有广泛应用。Jnc28资讯网——每日最新资讯28at.com

  1. 单例模式的主要优点包括:提供对唯一实例的受控访问,由于全局只存在一个实例,因此可以节约系统资源;允许扩展为可变数量的实例,既节约资源又解决过度共享影响性能的问题。
  2. 单例模式的主要缺点包括:没有抽象层导致扩展性差;违反单一职责原则,将实例化和业务逻辑混合在一起;在支持垃圾回收的运行时环境下可能导致状态丢失。
  3. 使用单例模式的典型场景包括:系统只需要一个实例;客户只能通过一个公共访问点获取实例;需要节约资源的频繁创建销毁对象。

总之,单例模式是一种利用率较高的设计模式,其限制实例个数的特点可以带来节省资源的优势,但也可能导致扩展性较弱以及与语言环境不够匹配等问题。在软件设计中,开发者需要权衡考虑系统的需求和优缺点,适当使用单例模式。Jnc28资讯网——每日最新资讯28at.com

Jnc28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-92-0.html三言两语说透设计模式的艺术-单例模式

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 从 Pulsar Client 的原理到它的监控面板

下一篇: 分布式系统中的CAP理论,面试必问,你理解了嘛?

标签:
  • 热门焦点
  • 雅柏威士忌多款单品价格大跌,泥煤顶流也不香了?

    来源 | 烈酒商业观察编 | 肖海林今年以来,威士忌市场开始出现了降温迹象,越来越多不断暴涨的网红威士忌也开始悄然回归市场理性。近日,LVMH集团旗下苏格兰威士忌品牌雅柏(Ardbeg
  • 破圈是B站头上的紧箍咒

    来源 | 光子星球撰文 | 吴坤谚编辑 | 吴先之每年的暑期档都少不了瞄准追剧女孩们的古偶剧集,2021年有优酷的《山河令》,2022年有爱奇艺的《苍兰诀》,今年却轮到小破站抓住了追
  • 自律,给不了Keep自由!

    来源 | 互联网品牌官作者 | 李大为编排 | 又耳 审核 | 谷晓辉自律能不能给用户自由暂时不好说,但大概率不能给Keep自由。近日,全球最大的在线健身平台Keep正式登陆港交所,努力
  • 花7万退货退款无门:谁在纵容淘宝珠宝商家造假?

    来源:极点商业作者:杨铭在淘宝购买珠宝玉石后,因为保证金不够赔付,店铺关闭,退货退款难、维权无门的比比皆是。“提供相关产品鉴定证书,支持全国复检,可以30天无理由退换货。&
  • 东方甄选单飞:有些鸟注定是关不住的

    文/彭宽鸿编辑/罗卿东方甄选创始人俞敏洪带队的“7天甘肃行”直播活动已在近日顺利收官。成立后一年多时间里,东方甄选要脱离抖音自立门户的传闻不绝于耳,“7
  • 阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的“征求意见版”:1、取消P序列
  • AI芯片初创公司Tenstorrent获三星和现代1亿美元投资

    Tenstorrent是一家由芯片行业资深人士Jim Keller领导的加拿大初创公司,专注于开发人工智能芯片,该公司周三表示,已经从现代汽车集团和三星投资基金等
  • 超级标准版旗舰!iQOO 11S全球首发iQOO超算独显芯片

    上半年已接近尾声,截至目前各大品牌旗下的顶级旗舰都已悉数亮相,而下半年即将推出的顶级旗舰已经成为了数码圈爆料的主流,其中就包括全新的iQOO 11S系
  • AI艺术欣赏体验会在上海梅赛德斯奔驰中心音乐俱乐部上演

    光影交错的镜像世界,虚实幻化的视觉奇观,虚拟偶像与真人共同主持,这些场景都出现在2019世界人工智能大会的舞台上。8月29日至31日,“AI艺术欣赏体验会”在上海
Top