在实例化时有对象依赖时如何实现单例

本文关键字:实现 单例 何实现 实例化 对象 依赖 | 更新日期: 2023-09-27 18:01:37

我有一个单例类,它需要实例化一个对象。

我使用这个方法来做:

  public static AppConfig Instance(IConfigManager configManager)
    {
        if (_instanceHolder == null)
        {
            lock (LockObject)
            {
                if (_instanceHolder == null)
                {
                    _instanceHolder = new AppConfig(configManager);
                }
            }
        }
        return _instanceHolder;
    }

在这种情况下实现单例是最好的方法吗?

谢谢

在实例化时有对象依赖时如何实现单例

在我看来,在这种情况下使用单例似乎是一个非常糟糕的主意。第二次调用将完全忽略 configManager参数,因为它会发现已经存在一个实例。在我看来,这违反了最小意外原则。

由于各种原因,单例模式通常令人讨厌,其中最重要的是可测试性。这个例子更糟糕——绝对不要用它。

另外,在实现单例模式时,我不会使用双重检查锁定。关于我的首选单例模式,请参阅我的文章。

似乎IoC容器将非常适合这种情况,例如(使用Ninject)。

IKernel kernel = new StandardKernel();
// register implementor of IConfiguration
kernel.Bind<IConfiguration>().To<Config>();
// register AppConfig as a singleton
kernel.Bind<AppConfig>().ToSelf().InSingletonScope();
...
// get the AppConfig singleton
var appConfig = kernel.Get<AppConfig>();

是双重检查Singletone模式。

一般来说,当我使用单例时,它只是为了重构一个更大的恶魔,即一个充满静态方法的类。当我需要为构造传递依赖时,我使用的一个技巧是使用两个"实例"方法(或者一个"构造"和一个"实例"方法):一个接受参数,一个不接受参数。接受参数的函数必须先调用,如果再次调用将抛出错误。如果在另一个版本之前调用无参数版本,则会抛出错误。

这意味着你在使用单例时必须小心,但至少你应该在运行时快速发现你是否做错了。我希望(在我和你的情况下)这只是迈向更好的道路上的一步。

我使用的是Java,但我认为c#的工作原理基本相同。

按照Jon的建议:

 public static void Initialize(IConfigManager configManager)
    {
        if (_instanceHolder == null)
        {
            lock (LockObject)
            {
                if (_instanceHolder == null)
                {
                    _instanceHolder = new AppConfig(configManager);
                    return;
                }
            }
        }
        throw new ApplicationException("Initalize() method should be called only once.");
    }
    /// <summary>
    /// Instances the specified config manager.
    /// </summary>
    /// <returns></returns>
    public static AppConfig Instance
    {
        get
        {
            if (_instanceHolder == null)
            {
                throw new ApplicationException("Singleton instance hasn't been initialized.");
            }
            return _instanceHolder;
        }
    }

,我调用它:

        void Application_Start(object sender, EventArgs e)
    {
        AppConfig.Initialize(new ConfigManagerWrapper());
    }

理想情况下,我应该为此使用IoC容器。但是我喜欢使AppConfig类具有默认实现,并使其能够用于依赖注入。在这种情况下,我不必在生产中调用Initialize()方法。