这里写的代码,相当于《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 }
完毕... ...
原标题:C#设计模式:单件(例)模式
关键词:C#