“小李啊,你在天文史上有的新的突破啊!”BOSS的腔调不像是在夸我。
“啊?”我满脸糊涂。
“你看,我在这天上发现了两个月亮啊!这不是新突破是什么?”BOSS转过它的液晶屏,指着屏幕说道。
“啊!该死!”我暗骂道。。。原来是前几天做了一个游戏项目中,游戏背景的天空中要根据游戏里的时间的不同出现一个与时间相符(形状,大小,位置等)的月亮的情景。当时是我写的月亮这一个类,我当时也没多想,就直接写成了(代码省略了具体实现):
public class Moon
{
public Moon()
{ }
public void DisplayMoon(Time time)
{
//根据时间的不同显示不同形状位置的月亮
}
//其它方法
}
{
public Moon()
{ }
public void DisplayMoon(Time time)
{
//根据时间的不同显示不同形状位置的月亮
}
//其它方法
}
没想到粗心的同事小张在调用我的类时竟在天上new出了两个月亮,最要重的是由于游戏里的时间是一致的,所以这两个月亮不管是形状,大小,位置在同一视有上都重叠了,一般人还真看不出这是两个月亮。可精明的BOSS切换一下视角。。。一下子原形毕露,天空上果然挂着两个月亮!
“这。。。调用时注意点应该没问题吧。。。”这是小张粗心,怎么怪到我头上啦。。我心想。
“类是你写的,你不觉得你应该在技术层上有所防范吗?天上有两个月亮这不应该啊!你这样让客户很担心啊!”BOSS有点语重心长。我知道BOSS这里的客户指的是调用这个类的客户代码。
“这。。。啊。。对了,有个模式可以防范多实例的产生。。。单例模式!”我记得以前看过些设计模式,当时也没留下啥印象,真是灵光一闪啊!
“知道还不快去改善!”BOSS的脸色终于有所缓和。
我连忙回到办公室,把单例模式(Singleton Pattern)重温了一遍,并深入地研究一番。
单例模式(Singleton):保证一个类仅有一个实例并提供一个访问它的全局访问点。
实现方法一:
class Singleton
{
//多线程singleton代码
private static volatile Singleton instance;
//volatile关键字可防止编译器对所申请的字段优化,以保持字段的最新状态
private static readonly object obj = new object();
private Singleton() //private 禁止外部构造
{ }
public static Singleton Intance
{
get
{
if (instance == null) //如果没有实例化则实例化
{
lock (obj) //锁定obj对象防止多线程访问
{
if (instance == null) //双检测
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
{
//多线程singleton代码
private static volatile Singleton instance;
//volatile关键字可防止编译器对所申请的字段优化,以保持字段的最新状态
private static readonly object obj = new object();
private Singleton() //private 禁止外部构造
{ }
public static Singleton Intance
{
get
{
if (instance == null) //如果没有实例化则实例化
{
lock (obj) //锁定obj对象防止多线程访问
{
if (instance == null) //双检测
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
实现方法二:
1 //通过静态实例实现,非惰性加载
2 public sealed class Singleton
3 {
4 //静态初始化在自己被加载时将自己实例例化,也称饿汉式单例类
5 private static readonly Singleton instance = new Singleton();
6 private Singleton(){}
7 public static Singleton Instance
8 {
9 get
10 {
11 return instance;
12 }
13 }
14 }
2 public sealed class Singleton
3 {
4 //静态初始化在自己被加载时将自己实例例化,也称饿汉式单例类
5 private static readonly Singleton instance = new Singleton();
6 private Singleton(){}
7 public static Singleton Instance
8 {
9 get
10 {
11 return instance;
12 }
13 }
14 }
这种实现简单,线程安全,缺陷主要是instance不是惰性加载的。准确的说是不一定是惰性加载的,因为我们无法得知instance
会在什么时候被初始化。
通过上面的温习,我重写了我那可怜的Moon类:
1 public sealed class Moon //sealed防止被继承子类实例化
2 {
3 private static volatile Moon moon;
4 private static readonly object obj = new object();
5
6 private Moon() //私有防止外部调用
7 { }
8
9 public static Moon GetMoon
10 {
11 get
12 {
13 if (moon == null)
14 {
15 lock (obj)
16 {
17 if (moon == null)
18 {
19 moon = new Moon();
20 }
21 }
22 }
23 return moon;
24 }
25 }
26
27 public void DisplayMoon(Time time)
28 {
29 //根据时间的不同显示不同形状位置的月亮
30 }
31 //其它方法
32 }
2 {
3 private static volatile Moon moon;
4 private static readonly object obj = new object();
5
6 private Moon() //私有防止外部调用
7 { }
8
9 public static Moon GetMoon
10 {
11 get
12 {
13 if (moon == null)
14 {
15 lock (obj)
16 {
17 if (moon == null)
18 {
19 moon = new Moon();
20 }
21 }
22 }
23 return moon;
24 }
25 }
26
27 public void DisplayMoon(Time time)
28 {
29 //根据时间的不同显示不同形状位置的月亮
30 }
31 //其它方法
32 }
至此,那该死的小张想NEW两个月亮在天上也不可能啦!对了,过两天还有个太阳类,正好依瓢画葫芦:)
单例模式应用场地举例:
1,在中国,一个男人也允许娶一个老婆,哪天哪位当程序员的朋友想实现Wife类时可要小心了,最好用上单例模式,免得在公司被老板骂,回家还让老婆质问:)
2,我们在窗体应用程序中经常做一个MDI例子,如想在窗体中实现一个快捷工具箱一样的子窗体时,要防止生成多个快捷工具箱,正好也用上Singleton.
3, 在数据库接池方面可应用单例模式,确保连接的正确性并可提高效率。
题外话一:
学习设计模式,相信很多朋友都会有这种感觉:让人迷惑的不是模式的结构或实现方法,而是很难把握在什么情况下使用哪种合适的模式,为什么要用模式等一些问题。
以我的经验来看,要学好设计模式,最重要的是理解!对OOP有深刻的理解,对一些基本原则有良好的把握,是提高程序设计水平的基础,才可能更好的把握设计模式的精髓所在。我们常说学东西要知其然,更要知其所以然,所以,本系列会以演化的眼光,希望能给读者起到引路的作用。
以我的经验来看,要学好设计模式,最重要的是理解!对OOP有深刻的理解,对一些基本原则有良好的把握,是提高程序设计水平的基础,才可能更好的把握设计模式的精髓所在。我们常说学东西要知其然,更要知其所以然,所以,本系列会以演化的眼光,希望能给读者起到引路的作用。
情景故事纯属构,如有雷同不管我的事:)
题外话二:打个小广告,C#中国论坛http://www.c-sharp.cn/近日开通了,希望愿在相关方面深入学习的朋友前去交流学习。。。我们会有专门的团队为您解决力所能及的一些问题。