欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > C# >内容正文

C#

单例模式以及在C#中的使用

发布时间:2023/12/18 C# 60 豆豆
生活随笔 收集整理的这篇文章主要介绍了 单例模式以及在C#中的使用 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

下面做一些简要的说明。

1.

单例模式(Singleton Pattern),又称作单件模式,当然也有一种诙谐的称谓:单身模式。在经典的GoF所著的《Design Patterns》一书中,对单例模式有着详尽的介绍,这本书网上有全文版本。

 

2.

单例模式的意图是保证一个类仅有一个实例,并且要提供一个全局访问点来访问这个实例。通常这个全局访问点是一个静态方法或者C#中的一个属性。

 

3.

在C#中,典型的单例模式实现方法可以如下:

public class Manager {     private static Manager Mgr;     //constructor must be private     private Manager() { }     //public and static, or you can change it to Property instead of Method.     public static Manager GetInstance()     {         if (Mgr == null)         {             Mgr = new Manager();         }         return Mgr;     } }

当外部需要Manager的实例时,可以调用GetInstance()这个静态方法。由于Manager类的构造器是私有的,这也就避免了其他方式实例化这个Manager类。GetInstance()方法内部的实现,保证了全局中只有一个Manager实例。

 

4.

问题肯定不会这么简单就被解决,比如在多线程环境中,上述代码就会有很大的隐患。

  • 有一种情况很常见:两个线程同时调用GetInstance()方法;
  • 当某一个线程由于Mgr为null而进入条件判断代码块的时候,而恰恰还没有执行实例化一个Manager对象,这时候另一个线程由于Mgr为null,所以也会进入这个条件语句中

上面两种情况,很显然都会创建Manager实例,这也就违背了单例模式的意图了。

利用C#的特性,我们可以把一个线程先锁住(lock),等到这个线程完成后,再让下一个线程访问GetInstance()方法:

private static readonly object syncObject = new object(); //public and static, or you can change it to Property instead of Method. public static Manager GetInstance() {     //double check     if (Mgr == null)     {         lock (syncObject)         {             if (Mgr == null)             {                 Mgr = new Manager();             }         }     }     return Mgr; }

代码中用到了双重检查锁定(double check locking)的技术,是为了提高性能考虑,因为C#中lock语句是很耗性能的。第一道检查,是基于如果Mgr不为null的时候就不需要lock了,提高性能。第二道检查,是基于两个线程同时通过第一道检查后,第一个线程解锁后,由于Mgr此时已经不为null,所以第二个线程就不用实例化Manager了。

 

5.

单例模式有两种实现方式,主要基于构建的方式不同:

  • 延迟初始化(Lazy Initialization),也叫“懒汉模式”:单例实例在第一次使用时被构建;
  • 热初始化(Eager Initialization),也叫“恶汉模式”:单例实例在类加载时创建
  • 前面创建单例模式的方式都属于延迟初始化。.NET 4.0以后提供了一个Lazy<T>泛型类,可以被应用于这个场景,省却代码的编写量。

    public class Manager {     private static Lazy<Manager> mgr = new Lazy<Manager>();           //version of Thread Safe     //private static Lazy<Manager> mgr = new Lazy<Manager>(true);           private Manager() { }     public static Manager GetInstance()     {         return mgr.Value;     } }

    Lazy<T>的构造器重载版本可以帮我们解决多线程的问题。

    C#使用静态初始化来完成单例模式中的热初始化。需要注意的是,不需要考虑多线程的问题,因为CLR会自动解决多线程同步的问题。如果程序经常要用到这个实例,运用热初始化可以显著提高性能。

    public class Manager {     private static readonly Manager mgr = new Manager();     private Manager() { }     public static Manager GetInstance()     {         return mgr;     } }

     

    6.

    StackOverflow中对于单例模式都是持否定态度的,比如这个:

    In theory: when you need to restrict the instantiation of an object to one instance. In practice: never.

    主要基于下面几个原因:

    • 违反了单一职责原则
    • 耦合度过大
    • 单元测试基本无法进行
    • 开发混淆,造成混乱。比如作为API提供的时候。

    总之,

    There‘s at most a can use but there no need.

    文章来源:http://laobian.me/2013/02/singleton-pattern-with-csharp.html

    转载于:https://www.cnblogs.com/luohengstudy/p/3141968.html

    总结

    以上是生活随笔为你收集整理的单例模式以及在C#中的使用的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。