73. 抵制单件模式的诱惑

来源:互联网 发布:男生油性皮肤知乎 编辑:程序博客网 时间:2024/05/21 18:38

抵制单件模式的诱惑

        单件模式解决了你的很多问题,知道你只需要一个单一的实例,你可以确定这个实例在使用前已经初始化了,它通过一个唯一的全局访问点让你的设计变得简单。有何理由不喜欢这个经典的设计模式呢?
        结果是,有很多理由。尽管很诱人,但经验显示大多数单件实际上的坏处比好处要多。不幸的是,这个额外的智慧并没有像它应该的那样广为传播,单件也继续让很多程序员感到充满了诱惑。但它是需要抵制的:
        · 单个实例的需求经常是假想出来的。很多场景中,将来不需要其它的实例只不过是一种猜测。在应用程序的设计中传播这种猜测性的属性一定会在某个时候导致痛苦。需求是会改变的。好的设计拥抱需求的改变,而单件则不会。
        · 单件在概念上彼此独立的代码单元中产生隐式的依赖。这是有问题的,既因为它们是隐藏的,也因为它们在单元中引入了不必要的耦合。当你尝试写单元测试时,代码的味道就变得刺鼻了。单元测试依赖于松耦合以及选择性地使用一个模拟的实现代替真正的实现。单件会阻止这种直接的模拟。
        · 单件也带有隐式的持续状态,这又会妨碍单元测试。单元测试依赖于各个测试之间的独立性,这样测试用例就能以任何顺序运行,而且程序也可以在执行某个测试用例之前设定为一个已知的状态。一旦引入了单件中的可变状态,这就很难实现了。此外,这种全局访问的持续状态让推理代码变得更加困难,特别是在多线程环境中。
        · 多线程给单件模式带了更多的陷阱。由于直接的锁定效率不高,所谓的双重检查锁定模式(DCLP)就广受欢迎。不幸的是,这可能是更进一步形式的致命诱惑。结果是在很多语言中,DCLP都不是线程安全的,而即便是线程安全的,仍然有机会出现一些微妙的错误。
        单件的清理可能是一个最终的挑战:
        · 单件不支持显式的结束,这在某些环境中可能是严重问题。比如,在一个插件架构中,某个插件只有在其它对象都清理后才能安全地卸载。
        · 程序结束时,单件的隐式地清理是没有顺序的。这在包含了互相依赖的单件的应用程序中就很麻烦,一个单件可能会访问其它已经销毁了的。
        这些之中的某些缺点可以通过引入额外的机制来克服,然而,随之而来的是代码额外的复杂度的增加,这本可以通过选择其它的设计来避免的。
        因而,严格限制自己仅在真正只安装一次的类上使用单件模式。不要随意地在代码中使用单件的全局访问点。取而代之的是,只能从一些定义良好的地方进行单件的直接访问,从可以通过接口为其它代码提供访问的地方。其它代码是未知的,所以不要依赖单件或者其它类是否实现了接口。这就打破了阻挠单件测试的依赖性,增强了可维护性。所以,下次考虑实现或者访问一个单件时,希望能暂停一下,三思。

原文:Resist the Temptation of the Singleton Pattern by Sam Saariste

原创粉丝点击