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没有关系,^_^。那么对于本例来说,全局访问点是什么呢?因为你和一个人有了婚约后才可以实现的东西都应该属于全局访问点的范畴,比如你因为有了婚约所以每年都需要到对方的家里拜访,比如别人因为知道你们有了婚约而对你们时常一起散步不再感到奇怪等等。

实例代码:
ContractedBlock.gifExpandedBlockStart.gif查看代码
 1None.gifusing System;
 2None.gifusing System.Collections.Generic;
 3None.gifusing System.Text;
 4None.gif
 5None.gifnamespace SingletonDemo
 6ExpandedBlockStart.gifContractedBlock.gifdot.gif{
 7InBlock.gif    class Program
 8ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 9InBlock.gif        sealed class GirlsEngagement
10ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
11InBlock.gif            private static GirlsEngagement girlsEngageent;
12InBlock.gif            private GirlsEngagement()
13ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
14ExpandedSubBlockEnd.gif            }

15ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//// <summary>
16InBlock.gif            /// 不适合在多线程的环境中使用,如果多个人同时追求一个人,没有任何的加锁机制,出问题的几率相当
17InBlock.gif            /// 大,^_^。
18InBlock.gif            /// </summary>
19ExpandedSubBlockEnd.gif            /// <returns></returns>

20InBlock.gif            public static GirlsEngagement GetGirlsEngagement()
21ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
22InBlock.gif                if (null == girlsEngageent)
23InBlock.gif                    girlsEngageent = new GirlsEngagement();
24InBlock.gif                return girlsEngageent;
25ExpandedSubBlockEnd.gif            }

26InBlock.gif
27InBlock.gif            private static object writerLock = new Object();
28ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//// <summary>
29InBlock.gif            /// 加锁太早,多个线程到达的时候会等待解锁,在并发环境中容易造成性能问题。
30InBlock.gif            /// </summary>
31ExpandedSubBlockEnd.gif            /// <returns></returns>

32InBlock.gif            public static GirlsEngagement GetGirlsEngagementWithLock()
33ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
34InBlock.gif                lock (writerLock)
35ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
36InBlock.gif                    if (null == girlsEngageent)
37InBlock.gif                        girlsEngageent = new GirlsEngagement();
38ExpandedSubBlockEnd.gif                }

39InBlock.gif                return girlsEngageent;
40ExpandedSubBlockEnd.gif            }

41ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//// <summary>
42InBlock.gif            /// Double check锁定,比较理想的方式了,只有在对象创建的时候有一点性能影响,一旦对象创建成功由于加锁
43InBlock.gif            /// 造成的性能影响就不存在了。
44InBlock.gif            /// </summary>
45ExpandedSubBlockEnd.gif            /// <returns></returns>

46InBlock.gif            public static GirlsEngagement GetGirlsEngagementWithDoubleCheck()
47ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
48InBlock.gif
49InBlock.gif                if (null == girlsEngageent)
50ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
51InBlock.gif                    lock (writerLock)
52ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
53InBlock.gif                        girlsEngageent = new GirlsEngagement();
54ExpandedSubBlockEnd.gif                    }

55ExpandedSubBlockEnd.gif                }

56InBlock.gif                return girlsEngageent;
57ExpandedSubBlockEnd.gif            }

58InBlock.gif
59ExpandedSubBlockEnd.gif        }

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

65InBlock.gif        sealed class EarlyCreatedGirlsEngagement
66ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
67InBlock.gif            private static EarlyCreatedGirlsEngagement girlsEngageent=new EarlyCreatedGirlsEngagement();
68InBlock.gif            private EarlyCreatedGirlsEngagement()
69ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif
70ExpandedSubBlockEnd.gif            }

71InBlock.gif            public static EarlyCreatedGirlsEngagement GetGirlsEngagement()
72ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
73InBlock.gif               return girlsEngageent;
74ExpandedSubBlockEnd.gif            }

75ExpandedSubBlockEnd.gif        }

76InBlock.gif
77InBlock.gif        static void Main(string[] args)
78ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
79InBlock.gif            GirlsEngagement g1 = GirlsEngagement.GetGirlsEngagement();
80InBlock.gif            GirlsEngagement g2 = GirlsEngagement.GetGirlsEngagement();
81InBlock.gif            Console.WriteLine(g1 == g2);
82InBlock.gif            Console.ReadKey();
83ExpandedSubBlockEnd.gif        }

84ExpandedSubBlockEnd.gif    }

85ExpandedBlockEnd.gif}

86None.gif


解释部分:
我尝试过使用多线程试图证实如果不加锁会生成多个singleton类的实例,但是很难成功,^_^,所以就把那部分代码删除了,如果谁能有好的办法证实这个问题,希望能告诉我。

对于单件中的加锁机制,大家可以参考《c#线程参考手册》,加锁的方式以及优劣分析的比较多。

Q/A:
1. 单件模式是不是应该用来继承,也就是把构造函数声明成protected?
不应该,因为一旦有了继承就会出现多个子类指向父类中 一个静态对象的引用,这不是我们想要的。

2.为什么不用静态全局变量代替单件模式?
静态全局变量只能在应用程序初始化的时候赋值,失去了单件模式中对象实时创建的灵活性,在资源比较珍贵的场景中尤其不是适合。



转载于:https://www.cnblogs.com/netboy/archive/2007/06/10/778115.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值