Head First Design patterns笔记-Singleton patterns (从“一夫一妻制社会中婚约的达成”看单件模式)
定义:The singleton pattern ensures a class has only one instance, and provides a global point of access to it.
背景介绍: 在“一夫一妻”制的社会中,受道德约束,每个人(虽然本例是用girl’s engagement,但是实际不论对于男人或者女生都是成立的,^_^。)一旦有了婚约就不应该再接受其他的婚约。不知道现在还有没有“指腹为婚”和“娃娃亲”,虽然这与现在提倡的“婚姻自由,自主婚姻”等观念格格不入,但是与“一夫一妻”制度是没有冲突的,而且对于本例是很有用的。“指腹为婚”和“娃娃亲”映射到本例,就是early created singleton object,GirlsEngagement实例在外界访问以前已经存在了,所以大家不要再去试图追求一个从小就有了婚约的人。现实生活中并不是一个追求者去追一个被追求者这么简单,更多的时候可能是一对多的关系,多个人同时追求一个人(多线程问题),这个时候会出现非常非常多的问题,如果没有任何限制,这个被追求者同时有了多个婚约,后果真的不堪设想啊!轻则会有各种各样的纠纷,重则可能会搞得头破血流,你死我活。追求一个自己心仪的对象如果想更大可能性拿到婚约,最好是让别人知道某人正在被你追,但是这个时候你也要搞清楚,你喜欢的人是不是已经有了婚约,别跟大家说你要追某MM,结果发现人家早在一年前就订婚了(加了锁,然后发现girl's engagement已经创建了),最后不得不中途退出。英明的人总是做double check, 先看你心仪的对象有没有婚约,如果没有就加锁,表明你的MM已经名花有主。彪悍的人不管MM有没有婚约甚至不管人家是不是已经结婚,总是要加锁,然后去达成和MM的婚约―――当然这个和本文的singleton pattern没有关系,^_^。那么对于本例来说,全局访问点是什么呢?因为你和一个人有了婚约后才可以实现的东西都应该属于全局访问点的范畴,比如你因为有了婚约所以每年都需要到对方的家里拜访,比如别人因为知道你们有了婚约而对你们时常一起散步不再感到奇怪等等。
实例代码:

查看代码
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
5
namespace SingletonDemo
6

{
7
class Program
8
{
9
sealed class GirlsEngagement
10
{
11
private static GirlsEngagement girlsEngageent;
12
private GirlsEngagement()
13
{
14
}
15
/**//// <summary>
16
/// 不适合在多线程的环境中使用,如果多个人同时追求一个人,没有任何的加锁机制,出问题的几率相当
17
/// 大,^_^。
18
/// </summary>
19
/// <returns></returns>
20
public static GirlsEngagement GetGirlsEngagement()
21
{
22
if (null == girlsEngageent)
23
girlsEngageent = new GirlsEngagement();
24
return girlsEngageent;
25
}
26
27
private static object writerLock = new Object();
28
/**//// <summary>
29
/// 加锁太早,多个线程到达的时候会等待解锁,在并发环境中容易造成性能问题。
30
/// </summary>
31
/// <returns></returns>
32
public static GirlsEngagement GetGirlsEngagementWithLock()
33
{
34
lock (writerLock)
35
{
36
if (null == girlsEngageent)
37
girlsEngageent = new GirlsEngagement();
38
}
39
return girlsEngageent;
40
}
41
/**//// <summary>
42
/// Double check锁定,比较理想的方式了,只有在对象创建的时候有一点性能影响,一旦对象创建成功由于加锁
43
/// 造成的性能影响就不存在了。
44
/// </summary>
45
/// <returns></returns>
46
public static GirlsEngagement GetGirlsEngagementWithDoubleCheck()
47
{
48
49
if (null == girlsEngageent)
50
{
51
lock (writerLock)
52
{
53
girlsEngageent = new GirlsEngagement();
54
}
55
}
56
return girlsEngageent;
57
}
58
59
}
60
61
/**//// <summary>
62
/// 实例在类被访问以前就创建好了,静态变量默认是线程安全的,但是使用这种方式就丧失了实时创建的
63
/// 灵活性,不论现在外部环境需不需要访问这个对象,总是存在,对于资源比较珍贵的场景来说并不合适。
64
/// </summary>
65
sealed class EarlyCreatedGirlsEngagement
66
{
67
private static EarlyCreatedGirlsEngagement girlsEngageent=new EarlyCreatedGirlsEngagement();
68
private EarlyCreatedGirlsEngagement()
69
{
70
}
71
public static EarlyCreatedGirlsEngagement GetGirlsEngagement()
72
{
73
return girlsEngageent;
74
}
75
}
76
77
static void Main(string[] args)
78
{
79
GirlsEngagement g1 = GirlsEngagement.GetGirlsEngagement();
80
GirlsEngagement g2 = GirlsEngagement.GetGirlsEngagement();
81
Console.WriteLine(g1 == g2);
82
Console.ReadKey();
83
}
84
}
85
}
86
解释部分:
我尝试过使用多线程试图证实如果不加锁会生成多个singleton类的实例,但是很难成功,^_^,所以就把那部分代码删除了,如果谁能有好的办法证实这个问题,希望能告诉我。
对于单件中的加锁机制,大家可以参考《c#线程参考手册》,加锁的方式以及优劣分析的比较多。
Q/A:
1. 单件模式是不是应该用来继承,也就是把构造函数声明成protected?
不应该,因为一旦有了继承就会出现多个子类指向父类中 一个静态对象的引用,这不是我们想要的。
2.为什么不用静态全局变量代替单件模式?
静态全局变量只能在应用程序初始化的时候赋值,失去了单件模式中对象实时创建的灵活性,在资源比较珍贵的场景中尤其不是适合。
背景介绍: 在“一夫一妻”制的社会中,受道德约束,每个人(虽然本例是用girl’s engagement,但是实际不论对于男人或者女生都是成立的,^_^。)一旦有了婚约就不应该再接受其他的婚约。不知道现在还有没有“指腹为婚”和“娃娃亲”,虽然这与现在提倡的“婚姻自由,自主婚姻”等观念格格不入,但是与“一夫一妻”制度是没有冲突的,而且对于本例是很有用的。“指腹为婚”和“娃娃亲”映射到本例,就是early created singleton object,GirlsEngagement实例在外界访问以前已经存在了,所以大家不要再去试图追求一个从小就有了婚约的人。现实生活中并不是一个追求者去追一个被追求者这么简单,更多的时候可能是一对多的关系,多个人同时追求一个人(多线程问题),这个时候会出现非常非常多的问题,如果没有任何限制,这个被追求者同时有了多个婚约,后果真的不堪设想啊!轻则会有各种各样的纠纷,重则可能会搞得头破血流,你死我活。追求一个自己心仪的对象如果想更大可能性拿到婚约,最好是让别人知道某人正在被你追,但是这个时候你也要搞清楚,你喜欢的人是不是已经有了婚约,别跟大家说你要追某MM,结果发现人家早在一年前就订婚了(加了锁,然后发现girl's engagement已经创建了),最后不得不中途退出。英明的人总是做double check, 先看你心仪的对象有没有婚约,如果没有就加锁,表明你的MM已经名花有主。彪悍的人不管MM有没有婚约甚至不管人家是不是已经结婚,总是要加锁,然后去达成和MM的婚约―――当然这个和本文的singleton pattern没有关系,^_^。那么对于本例来说,全局访问点是什么呢?因为你和一个人有了婚约后才可以实现的东西都应该属于全局访问点的范畴,比如你因为有了婚约所以每年都需要到对方的家里拜访,比如别人因为知道你们有了婚约而对你们时常一起散步不再感到奇怪等等。
实例代码:
1
using System;2
using System.Collections.Generic;3
using System.Text;4

5
namespace SingletonDemo6


{7
class Program8

{9
sealed class GirlsEngagement10

{11
private static GirlsEngagement girlsEngageent;12
private GirlsEngagement()13

{14
}15

/**//// <summary>16
/// 不适合在多线程的环境中使用,如果多个人同时追求一个人,没有任何的加锁机制,出问题的几率相当17
/// 大,^_^。18
/// </summary>19
/// <returns></returns>20
public static GirlsEngagement GetGirlsEngagement()21

{22
if (null == girlsEngageent)23
girlsEngageent = new GirlsEngagement();24
return girlsEngageent;25
}26

27
private static object writerLock = new Object();28

/**//// <summary>29
/// 加锁太早,多个线程到达的时候会等待解锁,在并发环境中容易造成性能问题。30
/// </summary>31
/// <returns></returns>32
public static GirlsEngagement GetGirlsEngagementWithLock()33

{34
lock (writerLock)35

{36
if (null == girlsEngageent)37
girlsEngageent = new GirlsEngagement();38
}39
return girlsEngageent;40
}41

/**//// <summary>42
/// Double check锁定,比较理想的方式了,只有在对象创建的时候有一点性能影响,一旦对象创建成功由于加锁43
/// 造成的性能影响就不存在了。44
/// </summary>45
/// <returns></returns>46
public static GirlsEngagement GetGirlsEngagementWithDoubleCheck()47

{48

49
if (null == girlsEngageent)50

{51
lock (writerLock)52

{53
girlsEngageent = new GirlsEngagement();54
}55
}56
return girlsEngageent;57
}58

59
}60

61

/**//// <summary>62
/// 实例在类被访问以前就创建好了,静态变量默认是线程安全的,但是使用这种方式就丧失了实时创建的63
/// 灵活性,不论现在外部环境需不需要访问这个对象,总是存在,对于资源比较珍贵的场景来说并不合适。64
/// </summary>65
sealed class EarlyCreatedGirlsEngagement66

{67
private static EarlyCreatedGirlsEngagement girlsEngageent=new EarlyCreatedGirlsEngagement();68
private EarlyCreatedGirlsEngagement()69

{ 70
}71
public static EarlyCreatedGirlsEngagement GetGirlsEngagement()72

{73
return girlsEngageent;74
}75
}76

77
static void Main(string[] args)78

{79
GirlsEngagement g1 = GirlsEngagement.GetGirlsEngagement();80
GirlsEngagement g2 = GirlsEngagement.GetGirlsEngagement();81
Console.WriteLine(g1 == g2);82
Console.ReadKey();83
}84
}85
}86

解释部分:
我尝试过使用多线程试图证实如果不加锁会生成多个singleton类的实例,但是很难成功,^_^,所以就把那部分代码删除了,如果谁能有好的办法证实这个问题,希望能告诉我。
对于单件中的加锁机制,大家可以参考《c#线程参考手册》,加锁的方式以及优劣分析的比较多。
Q/A:
1. 单件模式是不是应该用来继承,也就是把构造函数声明成protected?
不应该,因为一旦有了继承就会出现多个子类指向父类中 一个静态对象的引用,这不是我们想要的。
2.为什么不用静态全局变量代替单件模式?
静态全局变量只能在应用程序初始化的时候赋值,失去了单件模式中对象实时创建的灵活性,在资源比较珍贵的场景中尤其不是适合。

