你的位置:首页 > ASP.net教程

[ASP.net教程]C#设计模式:单件(例)模式


这里写的代码,相当于《Head First 设计模式》的读书笔记,原书是java的,自己在学习的过程中将其翻译为C#:

(一)剖析经典的单件模式实现

  单件模式

  -- 确保一个类只有一个实例,并提供一个全局访问点

  -- 单件模式的类图可以说是所有模式的类图中最简单的

  -- 有一些对象其实我们只需一个,如线程池、缓存、对话框、处理偏好设置和注册表的对象、日志对象和充当打印机、显卡等设备的驱动程序的对象等。如果制造出多个实例,可能导致许多问题,如程序的行为异常、资源使用过度,或者结果不一致等

 

  1.新建一个控制台应用程序:SingletonPatternDemo。

  2.新建一个类:Singleton.cs

 1 namespace SingletonPatternDemo 2 { 3   public class Singleton 4   { 5     /// <summary> 6     /// 利用一个静态变量来记录Singleton类的唯一实例 7     /// </summary> 8     private static Singleton _uniqueInstance; 9 10     //这里是其它变量...11 12     /// <summary>13     /// 构造器私有化:只能在类内部才能调用构造器14     /// </summary>15     private Singleton() { }16 17     /// <summary>18     /// 只能通过该方法获取到对象实例19     /// </summary>20     /// <returns></returns>21     public static Singleton GetInstance()22     {23       //【注意】如果我们不需要该实例,它就永远不会产生。这就是“延迟实例化”(lazy instantiaze)24       return _uniqueInstance ?? (_uniqueInstance = new Singleton());25 26       #region 上行相当于以下代码27       //if (_uniqueInstance == null)28       //{29       //  _uniqueInstance = new Singleton();30       //}31 32       //return _uniqueInstance;33       #endregion34     }35 36     //这里是其它方法...37   }38 }

  下面我们去掉注释看看

 1 namespace SingletonPatternDemo 2 { 3   public class Singleton 4   { 5     private static Singleton _uniqueInstance; 6  7     private Singleton() { } 8  9     public static Singleton GetInstance()10     {11       return _uniqueInstance ?? (_uniqueInstance = new Singleton());12     }13   }14 }

  哇塞,这么简单啊!如果你也这么认为的话,那就错啦......接下来,我们看下第(二)部分

(二)场景应用

  巧克力工厂

  现代化的巧克力工厂具备计算机控制的巧克力锅炉,锅炉做的事,就是把巧克力和牛奶融在一起,然后送到下一个阶段,以制造成巧克力棒。

  这里有一个Choc-O-Holic公司的工业强度巧克力锅炉控制器,用于控制锅炉的日常运作,比如:锅炉内为空时才可以加入原料、锅炉内存在原料并且尚未煮沸时才能够进行煮沸,还有排出牛奶和巧克力的混合物时要求炉内存在已经煮沸的原料等。

  下列是巧克力锅炉控制器的代码:

 1 namespace SingletonPatternDemo 2 { 3   /// <summary> 4   /// 巧克力锅炉 5   /// </summary> 6   public class ChocolateBoiler 7   { 8     private bool Empty { get; set; } 9     private bool Boiled { get; set; }10 11     //代码开始时,锅炉为空,未燃烧12     public ChocolateBoiler()13     {14       Empty = true;15       Boiled = false;16     }17 18     /// <summary>19     /// 填充20     /// </summary>21     public void Fill()22     {23       //在锅炉内填入原料时,锅炉必须为空;24       //填入原料后就把两个属性标识好25       if (Empty)26       {        27         //在锅炉内填满巧克力和牛奶的混合物...28 29         Empty = false;30         Boiled = false;31       }32     }33 34     /// <summary>35     /// 排出36     /// </summary>37     public void Drain()38     {39       //锅炉排出时,必须是满的,并且是煮过的;40       //排出完毕后将Empty标志为true。41       if (!Empty && Boiled)42       {43         //排出煮沸的巧克力和牛奶...44 45         Empty = true;46       }47     }48 49     /// <summary>50     /// 煮沸51     /// </summary>52     public void Boil()53     {54       //煮混合物时,锅炉必须是满的,并且是没有煮过的;55       //煮沸后,就把Boiled标识为true。56       if (!Empty && !Boiled)57       {58         //将炉内物煮沸...59 60         Boiled = true;61       }62     }63   }64 }

试试根据(一)中所学的内容将它修改成单例模式

 1 namespace SingletonPatternDemo 2 { 3   /// <summary> 4   /// 巧克力锅炉 5   /// </summary> 6   public class ChocolateBoiler 7   { 8     private static ChocolateBoiler _uniqueInstance; //【新增】一个静态变量 9 10     private bool Empty { get; set; }11     private bool Boiled { get; set; }12 13     //代码开始时,锅炉为空,未燃烧14     private ChocolateBoiler()  //【修改】原来是public15     {16       Empty = true;17       Boiled = false;18     }19 20     /// <summary>21     /// 获取ChocolateBoiler对象实例22     /// </summary>23     /// <returns></returns>24     public static ChocolateBoiler GetInstance() //【新增】一个静态方法25     {26       return _uniqueInstance ?? (_uniqueInstance = new ChocolateBoiler());27     }28 29     /// <summary>30     /// 填充31     /// </summary>32     public void Fill()33     {34       //在锅炉内填入原料时,锅炉必须为空;35       //填入原料后就把两个属性标识好36       if (Empty)37       {        38         //在锅炉内填满巧克力和牛奶的混合物...39 40         Empty = false;41         Boiled = false;42       }43     }44 45     /// <summary>46     /// 排出47     /// </summary>48     public void Drain()49     {50       //锅炉排出时,必须是满的,并且是煮过的;51       //排出完毕后将Empty标志为true。52       if (!Empty && Boiled)53       {54         //排出煮沸的巧克力和牛奶...55 56         Empty = true;57       }58     }59 60     /// <summary>61     /// 煮沸62     /// </summary>63     public void Boil()64     {65       //煮混合物时,锅炉必须是满的,并且是没有煮过的;66       //煮沸后,就把Boiled标识为true。67       if (!Empty && !Boiled)68       {69         //将炉内物煮沸...70 71         Boiled = true;72       }73     }74   }75 }

点击查看答案

 

【问题】万一同时存在多个ChocolateBoiler(巧克力锅炉),可能将发生很多糟糕的事情!... 敬请收看第(三)部分

 

(三)处理多线程

  现在,只要使用lock,就可以很简单地解决(二)中出现的问题了

 1 namespace SingletonPatternDemo 2 { 3   public class Singleton 4   { 5     /// <summary> 6     /// 利用一个静态变量来记录Singleton类的唯一实例 7     /// </summary> 8     private static Singleton _uniqueInstance; 9 10     private static readonly object Locker = new object();11 12     //这里是其它变量...13 14     /// <summary>15     /// 构造器私有化:只能在类内部才能调用构造器16     /// </summary>17     private Singleton() { }18 19     /// <summary>20     /// 只能通过该方法获取到对象实例21     /// </summary>22     /// <returns></returns>23     public static Singleton GetInstance()24     {25       //lock:迫使每个线程在进入该方法之前,需要等候别的线程离开该方法,26       // 也就是说,不会有两个线程可以同时进入该方法27       lock (Locker)28       {29         if (_uniqueInstance == null)30         {31           //【注意】如果我们不需要该实例,它就永远不会产生。这就是“延迟实例化”(lazy instantiaze)32           _uniqueInstance = new Singleton();33         }34       }35       36 37       return _uniqueInstance;38 39     }40 41     //这里是其它方法...42   }43 }

  但是,现在又出现了性能的问题!...

  方案一:使用“急切”创建实例,而不用延迟实例化的做法

 1 namespace SingletonPatternDemo 2 { 3   public class Singleton 4   {     5     //如果应用程序总是创建并使用单件实例,或者在创建和运行时方面的负担不太繁重,可以选择这种方法 6  7     //在静态初始化器中创建单件,这段代码保证了线程安全 8     private static readonly Singleton UniqueInstance = new Singleton(); 9 10     private Singleton() { }11 12     public static Singleton GetInstance()13     {14       return UniqueInstance;15     }    16   }17 }

  方案二:用“双重检查加锁”

 1 namespace SingletonPatternDemo 2 { 3   public class Singleton 4   { 5     private static Singleton _uniqueInstance; 6     private static readonly object Locker = new object(); 7  8     private Singleton() { } 9 10     public static Singleton GetInstance()11     {12       //检查实例,如果不存在,就进入同步区块13       if (_uniqueInstance == null)14       {15         lock (Locker)16         {17           if (_uniqueInstance == null)18           {19             //只有第一次才彻底执行这里的代码20             _uniqueInstance = new Singleton();21           }22         }23       }           24 25       return _uniqueInstance;26     }27 28   }29 }

  完毕... ...