|
第二种: 1.当我们对类实例化的时候,如果类里面的静态成员还未初始化,那么这个类的所有静态成员依据在类里面出现的次序初始化. 2.为静态成员分配内存空间,此时空间存储数据为0或null 3.执行静态成员的初始化语句(也就是赋值语句) 4.执行类的静态构造函数 5. 为普通成员分配内存空间,此时空间存储数据为0或null 6.执行普通成员的初始化语句(也就是赋值语句) 7. 执行类的构造函数 很明显,这样的话如果我们第二次实例化类,1,2,3,4也都不会被执行,只会执行5,6,7 二) 将public SqlDataReader ExecuteReader() 修改成 public static SqlDataReader ExecuteReader() 修改不修改关键看什么呢? 如果该方法无需保持或变动跟对象有关的状态,则说明该方法与任何实例无关.所以可设计成static方法 我们的ExecuteReader()满足上面条件,无需操持对象有关状态,而且无需变动跟对象有关的状态. 三) 将public class SqlHelper 修改为 public static class SqlHelper 经过上面的修改后.我们的SqlHelper已经是一个合适工具类,它无需被实例化使用abstract,无需被继承使用sealed 可是没有public abstract sealed class SqlHelper 但有static, 二者是等效的,称为静态类. Math类相信大家都用的很爽吧.比如Math.Abs()取绝对值等方法. 很明显Math也是做为一个工具类,所以在.Net中也被设计成静态类. 注意:有些朋友要说了,那SqlHelper可不可以使用单件模式设计. 可以,可是不合适.做为一个工具类,它根本无需被实例化,一次都不要. 有些朋友要说了,讲单件模式讲到哪里去了都不知道,但小菜觉得区分不好static,单件模式是用不好的.滥用误用更是不在话下. 接下来就正式来说单件模式吧! (只允许实例化一次) 1)第一种单件模式 public sealed class Singleton { private static readonly Singleton _instance = new Singleton(); private Singleton() { } public static Singleton Instance { get { return _instance; } } public void DoSomething() { Console.WriteLine("做些事情"); } } 接下来,我们来用用测试一下 static void Main(string[] args) { Singleton s1 = Singleton.Instance; Singleton s2 = Singleton.Instance; s1.DoSomething();//做些事情 s2.DoSomething();//做些事情 Console.WriteLine(object.ReferenceEquals(s1, s2));//是否为相同实例,true } 恩,不错.大家觉得上面的设计怎么样? 其一: 如果很看注性能的话,或者Singleton很浪费资源的话,使用lazy-init会比较好一点.当需要用时才初始化. 但通常上面的代码是够用的. 其二: 由于静态成员的初始化时间很难控制,所以如果是静态引用类型的话,放在静态构造函数中初始化会更加适合. 这里就用到了前面讲到的对象构造顺序.如果不清楚的话,建议拉到前面在看一下,很重要. 这也是Effective C#中有介绍. 所以代码修改为 public sealed class Singleton { private static readonly Singleton _instance; private Singleton() { } static Singleton() { _instance = Singleton(); } public static Singleton Instance { get { return _instance; } } public void DoSomething() { Console.WriteLine("做些事情"); } } 如果对性能不是太讲究的话,推荐该做法.而且适合多线程. 二)第二种单件模式lazy-init 1public sealed class Singleton 2{ 3 private static Singleton _instance; 4 5 private Singleton() 6 { } 7 8 public static Singleton Instance 9 { 10 get 11 { 12 if (_instance == null) 13 { 14 _instance = new Singleton(); 15 } 16 return _instance; 17 } 18 } 19 20 public void DoSomething() 21 { 22 Console.WriteLine("做些事情"); 23 } 24} 代码也很清晰,但该单件模式只适用于单线程.不适合与多线程 为什么呢? 线程1取Singleton.Instance执行到第12行if(_instance == null) 成立进入停下 线程2取Singleton.Instance执行到第12行if(_instance == null) 也同样成立 进入执行第14行_instance = new Singleton() 设为obj1 停下 线程1继续执行同样执行第14行_instance = new Singleton() 设为obj2 obj1与obj2是不同.已经不是单件,是双件了,线程越多,可能多件都有可能. 这样的话,很多朋友马上会相到把 if(_instance==null){/*省略*/}锁上.不就ok了. 那就进入第三种单件模式. 三)第三种单件模式 public sealed class Singleton { private static Singleton _instance; private static object _lockHelper = new object(); private Singleton() { } public static Singleton Instance { get { lock (_lockHelper) { if (_instance == null) { _instance = new Singleton(); } } return _instance; } } public void DoSomething() { Console.WriteLine("做些事情"); } } 看来该单件模式支持多线程,但看来并不是太聪明. 如果_instance已经被初始化,然后每次线程进入还是需要同步,很明显效率下降. 我们只需要第一次初始化的时候同步,之后不要同步是最好的.效率也高. 看来double-check即双检查,会大大提高效率. 那就进入第四种单件模式. |