常用设计模式学习-单例模式

个人理解:在代码运行期间使用单例模式实现的部分有且只有一个实例存在。

应用场景:一般配置文件读取,日志记录,还有部分数据库访问连接池等都可以设计成单例模式。

几种实现方式:

        这里以读取配置文件为例

        一个配置文件对象:

public class CustomConfig
{
public string EmailUserName { get; set; }//邮箱账号
public string EmailContentModel { get; set; }//邮箱内容模板
public string EmailPassword { get; set; }//邮箱密码

}

  

       config配置文件:

        

        单例模式一般分为饿汉懒汉两种方式。

     饿汉模式在类被加载时就将自己实例化,它的优点在于无须考虑多个线程同时访问的问题,可以确保实例的唯一性;从调用速度和反应时间角度来讲,由于单例对象一开始就得以创建,因此要优于懒汉式单例。但是无论系统在运行时是否需要使用该单例对象,由于在类加载时该对象就需要创建,因此从资源利用效率角度来讲,饿汉式单例不及懒汉式单例,而且在系统加载时由于需要创建饿汉式单例对象,加载时间可能会比较长。

  先看饿汉。

 public sealed class SingletonFourth_1
    {
        private static readonly CustomConfig Instance = new CustomConfig();
        public static CustomConfig GetInstance()
        {
            return Instance;
        }
        private  SingletonFourth_1()//禁止实例化
        {
        }
    }

  

public sealed class SingletonFourth_2
    {
        private static readonly CustomConfig Instance = null;
        static SingletonFourth_2()
        {
            Instance = new CustomConfig();
        }
      private SingletonFourth_2() { }//禁止外部实例化
        public static CustomConfig GetInstance()
        {
            return Instance;
        }
    }

  这两个只是写法不同,但是其实都是一样的。

      懒汉模式在第一次使用时创建,无须一直占用系统资源,实现了延迟加载,但是必须处理好多个线程同时访问的问题,这将导致系统性能受到一定影响。          

public sealed class SingletonFirst
    {
        private static CustomConfig _instance = null;
        public static CustomConfig Instance
        {
            get
            {
                if (_instance != null) return _instance;
                _instance = new CustomConfig();
                return _instance;
            }
        }

        private SingletonFirst()//禁止外部实例化
        {
        }
    }

  这是一个简单的懒汉,这种写法在单线程的时候不会出现太大的问题,但多个线程同时访问的时候就有可能同时创建多个实例,而且这多个实例不是同一个对象,虽然后创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。

      

public sealed class SingletonSecond
    {
        private static CustomConfig _instance = null;
        private static readonly object PadLock = new object();
        public static CustomConfig Instance
        {
            get
            {
                lock (PadLock)
                {
                    if (_instance != null) return _instance;
                    _instance = new CustomConfig();
                    return _instance;
                }
            }
        }
        private SingletonSecond()//禁止外部实例化
        {
        }
    }

  这种写法线程安全了,不过当两个线程同时访问的时候,还是会实例化两次,这样会产生不必要的消耗。

public sealed class SingletonThird
    {
        private static CustomConfig _instance = null;
        private static readonly object PadLock = new object();
        public static CustomConfig GetInstance()
        {
            if (_instance != null) return _instance;//这里检查是避免资源浪费,实例不存在才进入同步模块
            {
                lock (PadLock)
                {
                    if (_instance != null) return _instance;//同步模块再检查一次,如果不存在,就只需要同步创建一次
                    _instance = new CustomConfig();
                    _instance.EmailUserName = System.Configuration.ConfigurationManager.AppSettings["EmailUserName"];
                    _instance.EmailPassword = System.Configuration.ConfigurationManager.AppSettings["EmailPassword"];
                    _instance.EmailContentModel = System.Configuration.ConfigurationManager.AppSettings["EmailContentModel"];
                    return _instance;
                }
            }
        }
        private SingletonThird()//禁止外部实例化
        {
        }
    }

  这种方式是平时看到比较多的双重校验的方式了,在进入锁之前先检查一次。这种方式资源利用率比较高,但是如果是遇到大量操作,加锁会成为性能瓶颈。

  

 public sealed class SingletonFifth
    {
        private static class Inside
        {
            internal static readonly CustomConfig Instance = new CustomConfig()
            {
                EmailUserName = System.Configuration.ConfigurationManager.AppSettings["EmailUserName"],
                EmailPassword = System.Configuration.ConfigurationManager.AppSettings["EmailPassword"],
                EmailContentModel = System.Configuration.ConfigurationManager.AppSettings["EmailContentModel"]
            };
        }
        public static CustomConfig GetInstance() { return Inside.Instance; }
        private SingletonFifth()//禁止外部实例化
        {
        }
    }

  这种方式是通过静态内部类的方式实现的,在性能要求比较高时,就可以使用这种方式,从而避免频繁的加锁和解锁造成的资源浪费。

 

public sealed class SingletonSixth
    {
        private static readonly Lazy<CustomConfig> Lazy =
            new Lazy<CustomConfig>(() => new CustomConfig()
            {
                EmailUserName = System.Configuration.ConfigurationManager.AppSettings["EmailUserName"],
                EmailPassword = System.Configuration.ConfigurationManager.AppSettings["EmailPassword"],
                EmailContentModel = System.Configuration.ConfigurationManager.AppSettings["EmailContentModel"]
            });

        public static CustomConfig GetInstance()
        {
            return Lazy.Value;
        }
        private SingletonSixth()//禁止外部实例化
        {
        }
    }

  这种方式是通过.net4.0新增的Lazy<T>的类,它提供了线程安全的延迟加载的调用。

以上就是这两天了解到的单例模式实现方式,记下来防止以后找不到了。

参考:http://csharpindepth.com/Articles/General/Singleton.aspx#unsafe

        http://www.cnblogs.com/wuchanming/p/4486357.html

        http://cantellow.iteye.com/blog/838473

        

posted @ 2017-03-30 13:17  九元五分  阅读(259)  评论(0编辑  收藏  举报