单例模式[Singleton]

单例模式也是一种简单得不要不要的设计模式,但实用性还是很强滴。

顾名思义,单例,就是设计一种模式,让类只能有一个实例。这种需求满街可见。就看windows系统,回收站、任务管理器,就是典型的单例。用户无论怎么操作,都不可能出现两个回收站或任务管理器的。

知道其意义后,就开始设计吧,第一个模型

 1 using System;
 2 
 3 namespace Singleton
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             LadyGaGa MyGirl = LadyGaGa.GetLadyGaGa();
10             MyGirl.Dance();
11             MyGirl.Sing();
12         }
13 
14         public class LadyGaGa
15         {
16             /// <summary>
17             /// 构造函数的访问级别被定义成了私有,这样外部就没办法直接new出来啦
18             /// </summary>
19             private LadyGaGa() { }
20 
21             private static LadyGaGa ImTheOne;
22 
23             /// <summary>
24             /// 这里再提供一个访问ladygaga的方法
25             /// </summary>
26             /// <returns></returns>
27             public static LadyGaGa GetLadyGaGa()
28             {
29                 Console.Write("您成功邀请了Ladygaga参与你的party。当然,这个世界上如果特立独行的ladygaga只有一个");
30                 if (ImTheOne==null)
31                 {
32                     Console.WriteLine("哟西。ladyGaGa还没出生");
33                     ImTheOne = new LadyGaGa();
34                 }
35                 return ImTheOne;
36             }
37             public void Sing()
38             {
39                 Console.WriteLine("Can't read my. Can't read my. No he can't read my poker face");
40             }
41             public void Dance()
42             {
43                 Console.WriteLine("Ladgaga的舞蹈不是那么容易看到的。so hot");
44             }
45         }
46     }
47 }

想法的核心,就是不让外部直接实例化Ladygaga。只是针对C#,要知道构造函数是可以私有的。

就到这里,已经深得单例模式的精髓,但前面的做法。是没考虑到多线程访问的时候,这个写法不是很安全就在

1                 if (ImTheOne==null)
2                 {
3                     Console.WriteLine("哟西。ladyGaGa还没出生");
4                     ImTheOne = new LadyGaGa();
5                 }

这段代码上,如果两个线程,同一时间访问,两家判断到的结果都是null,然后两家都new一个,这时候的世界就不美妙了。因此版本二开始。

 1             public static LadyGaGa GetLadyGaGa()
 2             {
 3                 Console.Write("您成功邀请了Ladygaga参与你的party。当然,这个世界上如果特立独行的ladygaga只有一个");
 4                 lock (LockerObject)
 5                 {
 6                     if (ImTheOne == null)
 7                     {
 8                         Console.WriteLine("哟西,在这个有锁的世界里,我非常确定ladyGaGa还没出生,new 一个出来吧");
 9                         ImTheOne = new LadyGaGa();
10                     }
11 
12                 }
13                 return ImTheOne;
14             }

无非就是加个锁。让这个单例做得更安全。有性能要求或处女座程序猿的情况,会想到每次访问GetLadyGaGa都要加锁,不太爽,就能再优化下。第三版

 1             public static LadyGaGa GetLadyGaGa()
 2             {
 3                 Console.Write("您成功邀请了Ladygaga参与你的party。当然,这个世界上如果特立独行的ladygaga只有一个");
 4 
 5                 if (ImTheOne == null)
 6                 {
 7                     lock (LockerObject)
 8                     {
 9                         if (ImTheOne == null)
10                         {
11                             Console.WriteLine("哟西,在这个有锁的世界里,我非常确定ladyGaGa还没出生,new 一个出来吧");
12                             ImTheOne = new LadyGaGa();
13                         }
14                     }
15 
16                 }
17                 return ImTheOne;
18             }

这里的改动跟单例设计模式关系不大了,只不过想到

if (ImTheOne == null)被执行的概率很低,先不加锁判断下,非null就直接返回了嘛。

来一恶心的分介线---------------------------------------

单例模式还有什么要理解的?还真有:根据这个实例的实例发时间段,可分为饿汉,懒汉两种方式,专业的叫法是饿汉,懒汉。

饿汉:一开始就要准备好实例,其实叫贪婪方式更易懂。
懒汉:没召唤都不会有实例,对应就叫懒惰方式罗。
懒惰方式,上面coding就是一个典型的栗子,有人邀请ladgaga时,才会全世界地找ladygaga是否在人世。
贪婪方式就得好好利用static了。
 1         public class LadyGaGa
 2         {
 3             /// <summary>
 4             /// 构造函数的访问级别被定义成了私有,这样外部就没办法直接new出来啦
 5             /// </summary>
 6             private LadyGaGa() { }
 7 
 8             private static LadyGaGa ImTheOne=new LadyGaGa();
 9 
10             /// <summary>
11             /// 这里再提供一个访问ladygaga的方法
12             /// </summary>
13             /// <returns></returns>
14             public static LadyGaGa GetLadyGaGa()
15             {                
16                 return ImTheOne;
17             }
18             public void Sing()
19             {
20                 Console.WriteLine("Can't read my. Can't read my. No he can't read my poker face");
21             }
22             public void Dance()
23             {
24                 Console.WriteLine("Ladgaga的舞蹈不是那么容易看到的。so hot");
25             }
26         }

比起懒惰方式,贪婪模式写得真是简单粗暴。

个人就觉得,单例的用途上,跟一个static实例本身功能一至,但有时还真是得用单例,才能用上对象的特性,如继承。

而贪、懒方式上,要根据具体情况来选择,如对象本身实例化很漫长很庞大,应用启用又没有时效要求,就应该用贪婪方式啦。



 

posted @ 2017-03-18 17:34  小猪夏盈  阅读(101)  评论(0编辑  收藏  举报