辛格尔顿工厂的替代品

本文关键字:替代品 工厂 | 更新日期: 2023-09-27 18:27:54

我正在围绕一个我无法控制的类库编写一个包装器。在这个库中有一个类(让我们称之为Target),我想确保它只实例化一次,但它本身并不是一个单例。我想使用Singleton Factory模式,如下所示:

internal sealed class SingletonFactory
{
    private static readonly SingletonFactory manager = new SingletonFactory();
    private readonly Target target;
    private static SingletonFactory() { }
    private SingletonFactory()
    {
        target = new Target();
        target.Init("foo");
    }
    internal static SingletonFactory Instance
    {
        get { return manager; }
    }
    internal Target Target
    {
        get { return target; }
    }
}

然后我可以做:

var targetInstance = SingletonFactory.Instance.Target;

然后我想通过使工厂完全静态来简化这一点:

internal static class StaticFactory
{
    private static readonly Target target;
    private static StaticFactory()
    {
        target = new Target();
        target.Init("foo");
    }
    internal static Target Target 
    {
        get { return target; }
    }
}

并且对目标实例的访问变为:

var targetInstance StaticFactory.Target;

我确信这个StaticFactory是线程安全的,并且提供了对目标类的单个实例的全局访问。这有什么我没有想到的问题吗?

辛格尔顿工厂的替代品

我不确定你的构造函数是否真的是线程安全的,因为从技术上讲,它可以同时从不同的线程访问。您可以锁定private static readonly object Lock = new object();以在那里强制线程安全。

如果我们谈论的是C#4,您可能还想在这里查看Lazy<T>http://msdn.microsoft.com/de-de/library/ee792409.aspx.它支持线程安全创建模式LazyThreadSafetyMode,使您能够在安全性和性能之间找到折衷方案。

旁注:最后,不使用静态可能是更好的设计决策,因为您可以防止架构上不可见的依赖关系,并获得交换实现的能力。使用抽象工厂解决了这一问题(也提供了良好的单元测试体验)。

其实也是一样,只是你的静态构造函数上有private关键字,这是不允许的。

internal static class StaticFactory
{
    public static Target Target = new Target();
    static StaticFactory()
    {
       Target.Init("foo");
    }
}

你可以得到幻想,并将其全部推入懒惰:

public static Lazy<Target> Target =
      new Lazy<Target>(() => { var t = new Target(); t.Init(""); return t; });

您还可以建立一个facade,它将为您提供与Target相同的语义,但将其保留为一个实例。它还为您提供了在何时何地初始化Target对象的空间。

public class TargetFacade
{
   private static Target _target = new Target();
   static StaticFactory()
   {
      _target.Init("foo");
   }
   //Wrap Target's methods here.
   public int Score { get { return _target.Score } }; 
}