【问题标题】:Why use Lazy<T> instead of static factory class for singletons?为什么对单例使用 Lazy<T> 而不是静态工厂类?
【发布时间】:2017-09-15 09:30:02
【问题描述】:

在找到Lazy&lt;T&gt; 类型之前,我使用以下模式来实现全局单例:

class DataModel
{
    public static XmlSerializer Serializer
    {
        get { return SerializerFactory.instance; }
    }

    static class SerializerFactory
    {
        internal static readonly XmlSerializer instance =
            new XmlSerializer(typeof(DataModel));
    }    
}

这种模式具有以下优点:

  1. 类型初始化是惰性的。
  2. 类型初始化是线程安全的。
  3. 单例访问只是一种没有方法调用的直接字段访问。

最近我看到很多帖子建议Lazy&lt;T&gt; 实现类似的单例访问模式。 Lazy&lt;T&gt;(或LazyInitializer)会给这个实现带来什么好处?

【问题讨论】:

  • 我认为只有在构建这些实例成本高昂(时间、IO、内存方面)并且在启动时不会立即使用它时才有益。但一如既往:先衡量,然后根据证据做出决定。
  • 不是单身!它是一个延迟实例化的静态只读属性(属于 DataModel 类)。
  • 老实说,我建议您在 90% 的情况下对单身人士使用 nother 选项。我会改为使用 IoC 容器(例如 Autofac),将类注册为容器中的单例,然后照常注入。 从而使单元测试更容易。
  • "你对单例的定义是什么" - Singleton Pattern : "...单例模式是一种软件设计模式,它将类的实例化限制为一个对象" - 您可以拥有多个XmlSerializer 实例,因此它不是单例。从任何 DataModel 对象返回的实例都是相同的,仅此而已。

标签: c# singleton


【解决方案1】:

可读性

这是您的代码在使用Lazy&lt;T&gt; 实现时的样子:

class DataModel
{
    private static readonly Lazy<XmlSerializer> lazySerializer = 
       new Lazy<XmlSerializer>(() => new XmlSerializer(typeof(DataModel)));

    public static XmlSerializer Serializer
    {
        get { return lazySerializer.Value; }
    }
}
  1. 您需要更少的样板代码(没有内部类),
  2. 您的代码的目的对于阅读它的每个人立即显而易见
  3. 验证代码是否正确且线程安全要容易得多(无需了解细微的类型初始化细节,只需查看 Lazy&lt;T&gt;'s documentation 即可),
  4. 阅读您的代码的人不会想知道您为什么要重新发明轮子,以及内置功能是否可能存在一些细微差别。

【讨论】:

  • 你和 OP 缺少 private 无参数构造函数。使用表达式语法 getter 是 1 班轮。
  • 也许对于熟悉Lazy&lt;T&gt; 的人来说确实如此,但是当我第一次看到这样的代码时,它的目的并不是很明显。具体来说,您需要了解 Lazy&lt;T&gt; 类的语义,而我建议的模式使用纯语言结构。
  • @glopes 在您使用的模式中,您知道为什么instance 必须是只读字段而不是属性吗?你认为这个要求很明确吗?
  • @glopes 好吧,我认为我们只需要同意不同意使用假设关于语言的神秘知识的模式是一件好事的概念。在学习环境中,也许 - 但在生产代码中,不是那么多...... :)
  • @Sinatr 序列化程序是单例,而不是 DataModel。但是,我实际上错过了 Serializer 属性上的 static 限定符,我现在已修复。
【解决方案2】:

Lazy&lt;T&gt; 更具表现力。很明显,该值使用了延迟初始化。

例如,我在某些资源的初始化过于繁重而无法放入构造函数并且我不希望 API 使用者调用某些显式初始化例程的情况下使用它。

【讨论】:

    猜你喜欢
    • 2011-02-27
    • 2011-02-15
    • 1970-01-01
    • 2011-10-05
    • 2015-05-30
    • 1970-01-01
    • 2012-04-06
    • 2010-10-30
    相关资源
    最近更新 更多