【问题标题】:Alternative to Singleton-Factory单例工厂的替代方案
【发布时间】:2012-03-16 03:36:04
【问题描述】:

我正在编写一个我无法控制的类库的包装器。在这个库中有一个类(我们称之为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 是线程安全的,并且提供对目标类的单个实例的全局访问。这有什么我没有想到的问题吗?

【问题讨论】:

  • 您提到您对Target 没有任何控制权。您如何保证不会有人在您的工厂之外实例化 Target,尤其是在 Target 公开的情况下?
  • 我正在编写的包装库将隐藏Target 来自的程序集。这是一个公司内部项目,因此该库的使用量将相当小。

标签: c# singleton factory single-instance


【解决方案1】:

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

如果我们谈论的是 C# 4,您可能还想查看 Lazy<T> 此处 http://msdn.microsoft.com/de-de/library/ee792409.aspx。它支持线程安全的创建模式LazyThreadSafetyMode,让您可以在安全性和性能之间找到平衡。

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

【讨论】:

  • C# 中的线程安全单例已经讨论了很多。这是一个体面的演练。 yoda.arachsys.com/csharp/singleton.html 它比你想象的要容易。
  • 这实际上看起来不像我想象的那么容易。 :D 反正读起来很有趣!
  • 哦,我觉得无锁版挺简单的。
  • 当然,我只是发现它比锁定版本更难理解,因为这不是线程安全的。两个空的构造函数添加到这个。
【解决方案2】:

其实也一样,只是你的静态构造函数上有 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; });

您还可以建立一个外观,它会为您提供与 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 } }; 
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多