【问题标题】:Simpler Singleton Pattern更简单的单例模式
【发布时间】:2015-03-30 09:28:16
【问题描述】:

我一直在查看一些旧项目的一些代码,并在那里发现了一个单例。使用单例是必需的,我正在考虑一种方法让它在使用时看起来“更简单”。

我发现,像访问静态类一样访问方法和属性会更容易。所以我基本上使用静态方法实现了一个单例,以跳过使用GetInstance() 的要求。这就是我实现它的方式:

public class ExampleSingleton
{
    string someRequiredValue = "This is an example.";

    /// <summary>
    /// Private Constructor
    /// </summary>
    private ExampleSingleton() { }
    private static volatile ExampleSingletoninstance;

    /// <summary>
    /// !!! PRIVATE !!!
    /// Instance Property.
    /// Returns the instance of this singleton.
    /// (ThreadSafe)
    /// </summary>
    private static ExampleSingleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock (_lock)
                {
                    if (instance == null)
                    {
                        instance = new ExampleSingleton();
                    }
                }
            }

            return instance;
        }
    }

    /// <summary>
    /// Example field contains a value that should be
    /// accessible from outside.
    /// </summary>
    public static string SomeRequiredField
    {
        get
        {
            // Here you do the job you would have to do "outside"
            // of the class normally.
            return ExampleSingleton.Instance.someRequiredValue;
        }
    }

    // Helper for a secure thread synchronisation.
    private static object _lock = new object();
}

所以当你想访问单例值时,你可以这样做:

// Access the values like this
string requiredField = ExampleSingleton.SomeRequiredField;

// Instead of this
string requiredField = ExampleSingleton.Instance.SomeRequiredField;

// Or even this
string requiredField = ExampleSingleton.GetInstance().SomeRequiredField;

我在这里违反了单例模式的原则吗?它基本上仍然是单例模式,但获取实例的工作是在内部完成的。这个例子的缺点是什么?还有其他专业的吗?

谢谢

【问题讨论】:

  • 好问题。迫不及待地想看到人们来到这里把它放火,因为它是主观的......
  • @Orace 我相信,如果我问这种方法会出现什么问题,它不再是主观的了吗?
  • 我不会给出论据来扼杀你的问题 :o)
  • 如果你想节省一些输入,你可以这样做: private SingletonExample singletonExample = SingletonExample.Instance;在任何需要访问 Singleton 的地方,然后通过 singletonExample.SomeRequiredField 调用其属性;这不是一种常见的做法,而是一种可能性。

标签: c# design-patterns singleton


【解决方案1】:

在缺点方面,过去有两个咬过我:

  1. 由于 getter 是静态的,因此很难模拟单例
  2. 对单例接口的更改需要 2 个单独的更改(一个用于公共静态,一个用于内部)。

也就是说,我认为是这样的:

ExampleSingleton.Instance.SomeRequiredField

更容易模拟,因为您需要替换/还原 Instance 字段。关于“如何模拟静态这个或那个”的问题不时弹出,可能是由于您发布的类:

一般来说,C# 中的单例模式可能不是最好的主意,因为它们通常更难模拟,除非你将构造函数公开或使用 ioc 容器,但如果你需要一个,拥有一般来说,实例 getter 可能更容易测试。

第二点更多是关于代码的增量维护成本。基本上要“添加到类”,您有两点必须更改的代码:

class ExampleSingleton
{
    ... existing code ...

    public static int ComputeComplicatedMethod()
    {
        return ComputeComplicatedMethodImplementation();
    }

    private int ComputeComplicatedMethodImplementation()
    {
        // really complex code.
    }
}

因此,您基本上为每个新字段添加了一个额外的抽象层,而不是为获取实例字段添加一次。要么就是这样,要么你有一个使用内部静态单例的静态方法,如下所示:

class ExampleSingleton
{
    ... existing code ...

    public static int ComputeComplicatedMethod()
    {
        // use ExampleSingletonInstance here
    }
}

这实际上并不比仅仅拥有一个带有静态方法的静态类更好。一个更好的问题是为什么单例模式不只用一个静态类来实现?这可能在这里得到更好的解释:http://www.dotnetperls.com/singleton-static

【讨论】:

    【解决方案2】:

    我认为你必须选择代码最少的解决方案(但看起来人们喜欢写一堆没用的代码,所以你可能很难解释你的观点)。

    像您的示例中那样使用对属性的静态访问省了一个字:

    string requiredField = ExampleSingleton.SomeRequiredStuff;
    

    string requiredField = ExampleSingleton.Instance.SomeRequiredStuff;
    

    但是你必须为这个属性写getter。

    此外,如果您有很多属性,这会成为一个问题:您必须编写大量静态 getter。

    这不是标准并且违背了OOP精神:你处理一个对象的属性,所以得到对象然后是属性。

    另外如果你的值是不变的,那就不是属性!,习惯是把字段const和public。喜欢ulong.MaxValue

    为方法这样做看起来是个坏主意。 (同样在 OOP 中,方法属于对象)。如果您不想拥有任何静态的东西,则必须构建调用非静态函数的静态函数。维护起来会很不愉快。

    【讨论】:

    • 所以基本上它不是一种面向对象的方法。最初它会导致编写更少的代码,但如果单例变得更复杂,与标准方法相比,使用更多代码将难以维护。
    猜你喜欢
    • 2021-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多