代码改变世界

设计模式-单件模式

2012-06-09 10:04  chengzhang  阅读(135)  评论(0)    收藏  举报

1经典模式

    class Singleton

    {

        static Singleton instance;

        Singleton() { }

        public static Singleton Instance//静态属性?

        {

            get {

                if (instance == null)

                    instance = new Singleton();

                return instance;

            }

        }

    }

该类构造函数被定义为private,静态属性Instance是客户程序获得类型实例的唯一入口。if语句控制实例创建的数量。该方式在多线程环境下存在缺陷。当多个线程几乎同时调用该类的Instance属性方法时,Instance成员可能还没被实例化,故它可能被不同线程创建了多次,各个线程引用了不同的实例。

2改进 double check方式

    class Singleton

    {

        static volatile Singleton instance;

        Singleton() { }

        public static Singleton Instance

        {

            get {

                if (instance == null)

                    lock (typeof(Singleton))

                    {

                        if(instance == null)

                        instance = new Singleton();

                    }

                   

                return instance;

            }

        }

    }

说明:

1)  如果没有外层if,客户程序每次执行时都先lock住Singleton类型,但在绝大多数情况下,每次都锁定Singleton类型效率太差。

2)  lock加内层if构成了一个相对安全的实例构造环境。

3)  一旦唯一的实例被创建后,后续新发起的调用无须经lock部分,直接在外层if判断后就可获得既有的唯一实例引用。

4)  volatile关键字表示字段可能被多个线程修改。声明为volatile的字段不受编译器优化(一般默认的编译优化假定由单个线程访问)的限制,这样可以确保该字段在任何时间都呈现的是最新的值,即在被lock后,如果还没真正完成new Singleton(),新加入的线程看到的instance都是Null.

问题:构造过程为什么不放到静态构造函数中呢?

3多线程环境下实现单件模式的方式

    class Singleton

    {

        Singleton() { }

        public static readonly Singleton Instance = new Singleton();

}

说明

1)    Instance是类的公共静态成员,故它会在类第一次被用到的时候构造出来。这样就不用把它的构造语句显示写在静态构造函数中。是因为对其进行了初始化了吗?

2)    此单件模式是线程安全的

4

       public class Spooler   {

              static bool instance_flag = false; //true if one instance

              public Spooler()  {

              if (instance_flag)

                     throw new SingletonException("Only one printer allowed");

              else

                     instance_flag=true;     //set flag for one instance

              Console.WriteLine ("printer opened");

          }

       }

 

5需注意的地方

1)              不要实现ICloneable接口或继承自其相关的子类,否则客户程序可以跳过已经隐蔽起来的类构造函数。

2)              严防序列化。不能对期望具有Singleton特性的类型声明SerializableAttribute属性。