【问题标题】:Singleton Alternative - is it equivalent?Singleton Alternative - 是否等效?
【发布时间】:2012-02-26 08:37:28
【问题描述】:

我知道标准的单例模式如下:

原创

public class Singleton1
{

    public static Singleton1 _Instance;
    public static Singleton1 Instance
    {
        get
        {
            if (_Instance == null)
            {
                _Instance = new Singleton1();
            }
            return _Instance;
        }
    }

    private Singleton1()
    {

    }
}

但似乎这段代码是不必要的。对我来说,您可以使用以下任一简单的设计模式来完成同样的事情:

版本 2

public class Singleton2
{
    public static readonly Singleton2 Instance = new Singleton2();
    
    private Singleton2()
    {
    }
}

版本 3

public class Singleton3
{
    static Singleton3()
    {
    }
}

在我看来,版本 2 似乎是执行此操作的更好方法,因为它允许您传入(或不传入)参数但仍然有有限数量的实例。我的应用程序对延迟/性能非常敏感 - 这些模式中的任何一种都可以提高性能吗?

看起来虽然第一次访问每个对象的时间会更长,因为正在创建对象。此外,原来的似乎稍微慢了一点,因为每次其他东西访问它时,它都必须检查它的支持字段是否为空。

【问题讨论】:

标签: c# performance c#-4.0 singleton


【解决方案1】:
public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
    }
}

快速、干净、线程安全。

【讨论】:

    【解决方案2】:

    将单例实现为静态实例的一个问题是它们使测试和模拟变得更加困难。

    看这个场景:

    public void BusinessLogicMethod()
    {
        var initialValue = MySingleton.Instance.GetInitialValue();
        var processedValue = initialValue + specialSomething + businessLogic;
        MySingleton.Instance.SaveProcessedValue(processedValue);
    }
    

    现在,假设我想为此方法编写一个单元测试。理想情况下,我想编写一个指定输入和输出并仅测试业务逻辑的测试。但是对于静态单例,方法的实现与单例的实现相关联。我可以在测试开始时轻松设置 InitialValue,还是取决于其他因素/数据库访问/其他?

    但是,如果我使用非静态单例,再加上一些依赖注入或服务定位器模式,我可以像这样构建我的函数:

    public void BusinessLogicMethod()
    {
        var singleton = ServiceLocator.Resolve<MySingleton>();
        var processedValue = singleton.InitialValue + specialSomething + businessLogic;
        singleton.SaveProcessedValue(processedValue);
    }
    

    我的测试可以像这样进行,使用模糊的类似 Moq 的模拟语法:

    public void TestBusinessLogic()    
    {
        MySingleton fakeSingleton = new Mock<MySingleton>();
        fakeSingleton.Setup(s => s.InitialValue).Returns(5);
    
        // Register the fake in the ServiceLocator
        ServiceLocator.Register<MySingleton>(fakeSingleton.Object);
    
        // Run
        MyBusinessMethod();
    
        // Assert        
        fakeSingleton.Verify (s => s.SaveProcessedValue()).Called(Exactly.Once);
    } 
    

    不用担心真正的单例实现。

    【讨论】:

      【解决方案3】:

      Singleton2 与 Singleton1 不同,因为 Instance 不是“惰性”评估的。在 Singleton1 中,仅在访问实例时创建实例,然后使用同一个实例。在 SingleTon2 中,Instance 在实际访问之前使用类进行初始化。

      【讨论】:

        【解决方案4】:

        我最喜欢的单例实现是这个: http://www.codeproject.com/Articles/14026/Generic-Singleton-Pattern-using-Reflection-in-C

        确保您的 .ctor 不是公开的,这是最常见的错误,然后,它是安全/完全可重用的。

        (我需要仔细看看 Peter Kiss 的那个,看起来也不错)

        【讨论】:

          【解决方案5】:

          要回答您的性能问题,检查私有字段是否为空所需的时间可以忽略不计。因此,我不会担心它在性能方面是如何实现的。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-05-05
            • 1970-01-01
            • 2021-01-03
            • 2016-10-26
            • 2023-03-04
            • 2021-12-28
            相关资源
            最近更新 更多