ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【朝花夕拾】设计模式之单例模式

2019-04-05 10:47:59  阅读:205  来源: 互联网

标签:Singleton Lazy 模式 朝花夕拾 实例 线程 单例 设计模式


 

单例模式简介

单例模式是GOF 23个设计模式中最简单的模式了,它提供了一种创建唯一对象的最佳实现,注意此处的简单只是表述和意图很简单,但是实现起来,尤其是实现一个优美的单例模式却没有那么简单。

单例模式归根结底就是要确保一个类只有一个实例,并提供一个全局方式来访问该实例。具体而言,这种模式涉及到一个类,并由这个类创建自己的对象,同时确保只有单个对象被创建,并提供唯一一种方式来访问该对象的实例。

在现实生活中,单例的场景有很多,比如一夫一妻制(当然不道德的除外),比如一个部门只有一个领导等等。

单例模式UML类图

danli

 如上图所示:

1、单例类只能有一个实例。

2、单例类必须自己创建自己的唯一实例。

3、单例类必须给所有其他对象提供这一实例。

4、构造函数是私有的。

范例

Double-Check

我们先看一个非常流行而又简单的实现

   1:  public sealed class Singleton
   2:  {
   3:      private static Singleton instance = null;
   4:      private static readonly object padlock = new object();
   5:   
   6:      private Singleton()
   7:      {
   8:      }
   9:   
  10:      public static Singleton Instance
  11:      {
  12:          get
  13:          {
  14:              if (instance == null)
  15:              {
  16:                  lock (padlock)
  17:                  {
  18:                      if (instance == null)
  19:                      {
  20:                          instance = new Singleton();
  21:                          //Do a heavy task
  22:                      }
  23:                  }
  24:              }
  25:              return instance;
  26:          }
  27:      }
  28:  }

上述解决方案上,使用到了Double-Check方式,Double-Check方式可以说是盛名已久了,线程A与线程B在Null Check时同时通过,但是在Lock时,只能进入一个线程,其他线程都要等着。

这种方式在Java中编写单例模式的时候是失效的,具体原因我没有去深究。知乎上有人说过内存屏障技术(Memory Barrier),不过这段涉及到底层操作,一般很难有人会显示操作。另外一点就是,如果单例过程中操作的是一个数组或者其他对象,那么在实例化后如果需要进行赋值等运算操作的,那么其他线程在进行Null Check的时候就不会再次进入,如果其他线程调用了这个单例对象的某个属性,这极有可能出现难以预测的bug

Lazy

那么有没有其他方式优雅而又安全的实现单例模式呢,答案是有的,那就是通过Lazy方式,Lazy方式可以拥有更高的性能,因为实例只有在使用的时候才会真正创建对象,这就在很大程度上减少了内存的占用,当然,比较如果是比较简单的单例创建,可以忽略这条不利影响。

Lazy自带Double-Check,是线程安全的,他就像一个盾牌,在创建过程中,不管是创建简单对象还是复杂对象,都不会允许其他线程使用尚未创建完成的对象,更多的Lazy使用,请参考MSDN。

   1:  public sealed class Singleton
   2:  {
   3:      private Lazy<Singleton> lazy;
   4:   
   5:      public Singleton Instance { get { return lazy.Value; } }
   6:   
   7:      public string Name{get;set;}
   8:   
   9:      public Singleton()
  10:      {
  11:          lazy = new Lazy<Singleton>(InitializeSingleton);
  12:      }
  13:   
  14:      private Singleton InitializeSingleton()
  15:      {
  16:          Singleton singleton = new Singleton();
  17:          singleton.Name="Test";
  18:          return singleton;
  19:      }
  20:  }
<style></style>

单例模式优缺点

优点:

全局范围内只有一个实例,避免了内存消耗,以及实例频繁的创建和销毁。

避免了对资源的多重占用,比如独占式场景中。

缺点:

一旦对象指向的外部环境发生了变化,比如在网络调用、MQ等场景中一般可以可以采用单例,但是这里需要提醒的是,如果DNS发生异常,在异常期间将会出现极难修复的情况,除非手动重启并指向新的域服务器

这一点有点违反单一职责原则,通常情况下,一个类应该只关注自身逻辑而不是创建对象

有些地方会说单例模式没有接口,无法继承,但单例模式会为系统创建全局访问点,这个时候继承与不继承其实已经没有太大影响了

标签:Singleton,Lazy,模式,朝花夕拾,实例,线程,单例,设计模式
来源: https://www.cnblogs.com/edison0621/p/10658104.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有