C语言C#设计模式之一单例模式(Singleton Pattern)【创建型】

一、引言

    
看了李建忠先生的称的设计模式已经有一段时间了(这段日子大约有相同年多了),自己还尚无写了自己之、有关设计模式的稿子。这次纪念写有关于设计模式的章,用自己之知情与代码来形容,算是复习一尽。写作之历程被也会见多省其他大牛的文章,争取为好之知晓科学,否则把大家带来跑偏了,就是自家之错误了。今天就算开我们首先单设计模式,该模式是:【单例模式】,英文名称:Singleton
Pattern,这个模式很简短,一个路只待一个实例,他是创建型的设计模式。为什么让“创建项目”设计模式呢,因为她们出分类。当然了分类的方式不均等,分类的结果也就算不相同。

    从目的来拘禁:

      
-创建型(Creational)模式:负责对象创建

      
-结构型(Structural)模式:处理接近和目标中的整合

      
-行为型(Behavioral)模式:类以及目标交互中之任务分配

   从范围来拘禁:

     
-类模式处理接近及子类的静态关系

     
-对象模式处理对象中的动态关系

 
以上就是是分类的法子,我们本大多数底分类,采用“从目的来拘禁”的归类来对设计模式进行分拣,我们就是从头今天之修吧。

老二、单例模式的介绍
   2.1、动机(Motivate)

          在软件系统中,经常闹这般一些非常的类,必须确保它于网遭到才设有一个实例,才能够担保其的逻辑是、以及良好的效率。

    
如何绕了正常的构造器,提供平等种体制来保证一个看似才来一个实例?

        
这应是看似设计者的事,而休是使用者的义务

   2.2、意图(Intent)

         保证一个类就发生一个实例,并提供一个拖欠实例的全局访问点。                                  
–《设计模式GoF》

   2.3、结构图(Structure)

       C语言 1

  2.4、模式的咬合

        
(1)、单件实例(Singleton):这个模式里面只发生一个种类,就是Singleton类型,并且这仿佛才生一个实例,可以经Instance()方法获得该种的实例。

  2.5、单件模式的代码实现
        
既然是特实例,肯定会干到几近线程的题目,我们不怕同样步一步之来描写代码,我们先瞧单线程Singleton模式的贯彻,代码如下:

 1 /// <summary>
 2 /// 单例模式的实现
 3 /// </summary>
 4 public sealed class Singleton
 5 {
 6     // 定义一个静态变量来保存类的实例
 7     private static Singleton uniqueInstance;
 8  
 9     // 定义私有构造函数,使外界不能创建该类实例
10     private Singleton()
11     {
12     }
13  
14     /// <summary>
15     /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
16     /// </summary>
17     /// <returns></returns>
18     public static Singleton GetInstance()
19     {
20         // 如果类的实例不存在则创建,否则直接返回
21         if (uniqueInstance == null)
22         {
23             uniqueInstance = new Singleton();
24         }
25         return uniqueInstance;
26     }
27 }

   
私有的实例构造器是遮掩外界的调用,上面的单例模式之落实以单线程下确实是无微不至的,也大好的满足了咱单线程环境之急需。

    单线程单例模式的几乎独中心:

   
(1)、Singleton模式受到的实例构造器可以安装也protected以允许子类派生。

   
(2)、Singleton模式相似不要支持ICloneable接口,因为马上也许会见导致多只对象实例,与Singleton模式的初衷背道而驰。

   
(3)、Singleton模式相似不要支持序列化,因为马上吗出或致多独目标实例,同样与Singleton模式之初衷背道而驰。

   
(4)、Singletom模式只考虑到了靶创建的工作,没有设想对象销毁之做事。为什么这么做呢,因为Net平台是永葆垃圾回收的,所以我们一般没必要对那个进行销毁处理。

   
(5)、不能够回应多线程环境:在差不多线程环境下,使用Singleton模式仍然发生或赢得Singleton类的几近只实例对象

   
如果放在多线程环境下,问题就出去了。因为以有限个线程同时运转GetInstance方法时,此时星星点点单线程判断(uniqueInstance
==null)这个标准时犹回到真,此时少独线程就还见面创Singleton的实例,这样就是失了我们单例模式初衷了。要想缓解是题材,只要吃GetInstance方法在同一时间只运行一个线程运行就好了,让咱们看多线程Singleton模式的实现,代码如下:

 1     /// <summary>
 2     /// 单例模式的实现
 3     /// </summary>
 4     public sealed class Singleton
 5     {
 6         // 定义一个静态变量来保存类的实例
 7         private static volatile Singleton uniqueInstance;
 8  
 9         // 定义一个标识确保线程同步
10         private static readonly object locker = new object();
11  
12         // 定义私有构造函数,使外界不能创建该类实例
13         private Singleton()
14         {
15         }
16  
17         /// <summary>
18         /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
19         /// </summary>
20         /// <returns></returns>
21         public static Singleton GetInstance()
22         {
23             // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
24             // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
25             // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
26             lock (locker)
27             {
28                 // 如果类的实例不存在则创建,否则直接返回
29                 if (uniqueInstance == null)
30                 {
31                     uniqueInstance = new Singleton();
32                 }
33             }
34  
35             return uniqueInstance;
36         }
37     }

   
上面这种解决方案确实好缓解多线程的问题,但是地方代码对于每个线程都见面对线程辅助对象locker加锁之后再也判断实例是否在,对于此操作了没必要的,因为当第一只线程创建了此类的实例之后,后面的线程此时特待直接判断(uniqueInstance==null)为假,此时通通没有必要对线程辅助对象加锁之后再次去看清,所以地方的贯彻方式充实了额外的开发,损失了性,为了精益求精地方实现方式的毛病,我们只是待以lock语句前面加同词(uniqueInstance==null)的判定即便得避锁所加的额外开销,这种实现方式我们即便为它
又锁定(Double
Check)
”,下面具体看实现代码的:

 1     /// <summary>
 2     /// 单例模式的实现
 3     /// </summary>
 4     public sealed class Singleton
 5     {
 6         // 定义一个静态变量来保存类的实例
 7         private static volatile Singleton uniqueInstance;
 8  
 9         // 定义一个标识确保线程同步
10         private static readonly object locker = new object();
11  
12         // 定义私有构造函数,使外界不能创建该类实例
13         private Singleton()
14         {
15         }
16  
17         /// <summary>
18         /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
19         /// </summary>
20         /// <returns></returns>
21         public static Singleton GetInstance()
22         {
23             // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
24             // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
25             // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
26             // 双重锁定只需要一句判断就可以了
27             if (uniqueInstance == null)
28             {
29                 lock (locker)
30                 {
31                     // 如果类的实例不存在则创建,否则直接返回
32                     if (uniqueInstance == null)
33                     {
34                         uniqueInstance = new Singleton();
35                     }
36                 }
37             }
38             return uniqueInstance;
39         }
40     }

        volatile修饰:编译器在编译代码的时节会对代码的依次进行微调,用volatile修饰保证了从严意义之次第。一个定义为volatile的变量是说这变量可能会见吃意外地改变,这样,编译器就非会见失掉要是变量的值了。精确地游说哪怕是,优化器在就此到是变量时得每次都小心地重读取这个变量的值,而无是用保存在寄存器里之备份。

三、C#受到落实了单例模式的类
    现在咱们看,如何使用C#语言的表征来贯彻单例的Singleton模式。

//Singleton模式的实现
public sealed class Singleton
{
   public static readonly Singleton instance=new Singleton();

   private Singleton(){}
}

以上是内联初始化(生成的同时进行初始化)的单例模式,它等同于:

public sealed class Singleton
{
    public static readonly Singleton instance;

    //静态构造函数,CLR只执行一次
    static Singleton()
    {
       instance=new Singleton();
    }

   //私有构造函数,防止外界调用
   private Singleton(){}
}

   
内联初始化其实是把静态的字段放到静态构造器去初始化。只要想访问静态字段,必定已经当头里实施了静态构造器。这样呢能够规范地保管使用的时势必能用到实例,如果无下也无见面实例化对象,也不怕是延时加载的作用。他一致能够支持多线程环境,因为光可能产生一个线程执行静态构造器,不容许有差不多个线程去实践静态构造器,感觉就是是次已经自行吗我们加锁了。

     它们的某些弊就是它不支持参数化的实例化方法。在.NET里静态构造器只能声明一个,而且得是随便参数的,私有的。因此这种艺术单适用于无参数的构造器。

    
需要验证的凡:HttpContext.Current就是一个单例,他们是由此Singleton的扩充方式贯彻的,他们的单例也并无是盖所有世界,只是对一些局部领域中,是单例的,不同之小圈子面临尚是碰头产生例外的实例。

**四、Singleton模式之壮大

**

    
(1)、将一个实例扩展至n个实例,例如对象池的兑现。(n不是指太个实例,而是一定的某个数)

    
(2)、将new构造器的调用转移到任何类似吃,例如多个像样协同工作环境遭到,某个局部环境就需要持有某个类的一个实例。

    
(3)、理解和扩张Singleton模式的着力是“如何决定用户用new对一个好像的实例构造器的人身自由调用”。

五、总结

   
到这里,单例模式就是介绍完了,这个模式大粗略,理解起来呢不是不行不便,只要把住代码的贯彻技术,一般问题还未要命,但是只要物色好以的机会,如果利用不当,一些逻辑错误比较难以消查。