里面有两种写单例的例子.有一种方法得到资深工程师的否定.事实证明他的想法是错误的。
第一种:
public class Singleton
2{
3 private static Singleton _instance = null;
4 private static readonly object lockHelper = new object();
5 private Singleton()
6 {
7 }
8 public static Singleton CreateInstance()
9 {
10 //这样lock以及lock块内的代码只会在第一次调用CreateInstance方法的时候执行,
11 //第一次调用该方法后_instance就不再为null了,if块内的代码就无须执行了
12 if(_instance == null)
13 {
14 lock(lockHelper)
15 {
16 if(_instance == null)
17 _instance = new Singleton();
18 }
19 }
20 return _instance;
21 }
22}
这种方法也是大家公认的能够在多线程下面正常工作的一种方法.
原文中还提到了一种方法:
实际上在很多地方我们可以采用另外一种初始化的方式,特别对于哪些实时系统或者哪些系统随时都会用的类(比如系统配置类),我们用另外一种实现方法就不需要考虑线程安全的问题了,它们的线程安全由.net运行时为我们作保证。
1public class Singleton
2{
3 //先实例化出一个实例再说
4 private static Singleton _instance = new Singleton();
5 private Singleton(){}
6 public static Singleton CreateInstance()
7 {
8 return _instance;
9 }
10}
2{
3 //先实例化出一个实例再说
4 private static Singleton _instance = new Singleton();
5 private Singleton(){}
6 public static Singleton CreateInstance()
7 {
8 return _instance;
9 }
10}
博主说这两种方法都可以,我自己也不太清楚它们之间的区别,但是本人记忆力好,记下了.
一次在中软面试中,有一个题让你写一个单例模式例子出来,我想都没想就把上面第二种方法写出来了,当然我忘了写私有构造函数.这个也不影响思路.但是他们的技术人员说这不是单例模式,因为每次初始化类的时候就会new一次.
private static Singleton _instance = new Singleton();他可能是说这个.
之后我亲自测试了下博主说的第二种方法,说明是可行的,并非多线程.起码单线程是可以的.
我想他的意思应该是这样的:
public class Singleton2
{
//先实例化出一个实例再说
private static Singleton2 _instance = null ;
private DateTime _stime;
public DateTime sTime
{
get { return this._stime; }
set { this._stime = value; }
}
private Singleton2()
{
this.sTime = DateTime.Now;
}
public static Singleton CreateInstance()
{
if (_instance == null)
{
return new Singleton2();
}
else
{
return _instance;
}
}
}
{
//先实例化出一个实例再说
private static Singleton2 _instance = null ;
private DateTime _stime;
public DateTime sTime
{
get { return this._stime; }
set { this._stime = value; }
}
private Singleton2()
{
this.sTime = DateTime.Now;
}
public static Singleton CreateInstance()
{
if (_instance == null)
{
return new Singleton2();
}
else
{
return _instance;
}
}
}
经过我的测试,第三种代码是不正确的.
我在MSDN上查了关于static的解释:
static
修饰符指明成员属于类本身而不属于类的实例。即使创建了类的多个实例,给定应用程序中只存在 static 成员的一个副本。您只能通过对类的引用(而不是对实例的引用)来访问 static 成员。但是,在类成员声明中,可以通过 this 对象来访问 static 成员。
类的成员可以使用 static 修饰符来标记。类、接口和接口的成员不能采用 static 修饰符。不能将 static 修饰符与任何继承修饰符(abstract 和 final)或版本安全修饰符(hide 和 override)组合。
这就说明了博主的说法是正确的,无论初始化多少次类,但是只会存在静态成员的一个副本.
据说那个面试官是特别资深的工程师,他应该也有他的理由说那不是单例,我想让大家给说说第二种代码是否是真正的单例模式.
谢谢大家对的帮助,今天回家看了下《HEAD FIRST 设计模式》在P181中明确的说明了上文中的第二种方法是可行的,也是真正的单例模式:
原文是这样的:
2。使用“急切”创建实例,页不用延迟实例化的做法
如果应用程序总是创建并使用单件实例,或者在创建和运行时方面的负担不太繁重,你可能想要急切(eagerly)创建此单件,如下所示:
代码和上文中第二种方法是一模一样的。还特意对:private static Singleton _instance = new Singleton();这条语句进行说明:
在静态初始化器中创建单件,这段代码保证了线程安全。
本文中第一种创建单件的方法属于延迟实例化的做法,只有当第一次调用的时候才会实例化类,没有用到时则不进行任何实例化操作。所有说当类实例化不是特别复杂,对服务器开销不大的时候这两种方法在最终作用上和效果上是一样的,没有本质区别。所以最后本人认为我面试中的面试官的观点是错误的。如果有理解错误的地方还望指点。