为什么单例模式是邪恶的(译)
虽然这篇文章不是我写的,但我完全同意文章中的观点。Brian Button可能是我所知道的最有才的人之一。我相信他会喜欢你们的反馈的。
1、单例模式经常被用来为某些服务提供一个全局访问点
没错,是可以这么做,但代价是什么呢?众所周知,单例模式为你的应用程序中的某些服务提供全局访问点,这样你就不必到处传递一个该服务的引用。这和一个全局变量有什么区别呢?(记住,全局变量是不好的,不是吗?)最终会发生的事情便是你设计中的依赖关系是隐藏在代码中的,这种依赖关系不能够通过检查你的类和方法的接口所见。你必须检查代码以便准确地知道你的类中都用了哪些其他对象。这可能会是不清楚的(译者注:不知道是不是这么翻译,原文:This is less clear than it could be)。冲动地创建一个全局性的东西来避免把其传来传去是你设计中的异味,这不是全局变量或者单例的功能。如果你更仔细地检查你的设计,你几乎总是能想到一种不必把“流浪数据”四处传递到每个对象和方法的更好的设计。
2、单例模式允许你限制你所创建的对象的数量
这也是对的,但是现在你混合了两个不同的职责到同一个类中了,这是违反了单一职责原则的。一个类不应该关心它是否是一个单例,它应该仅仅关心它的业务职责。如果你想限制某些类的实例化能力,创建一个封装了创建并且如你所愿的那样限制创建能力的工厂或者对象生成器,这样创建职责便从业务实体职责中划分出来了。
3、单例模式促进了类之间的紧耦合
使代码是可测试的一个基本属性便是它和其周围环境是松耦合的。这个属性允许你在测试过程中为了实现特定的测试目标(想想模拟对象)替换备用的合作者。单例模式把单例对象的确切类型紧耦合在一起,丧失了使用多态来替换的机会。一个更好的选择,如上面第一点所讨论到的,便是改变你的设计以便允许你传递对象的引用到你的类和方法中,这样可以减轻上述的耦合问题。
4、单例模式在程序的持续过程中一直保存着上一次的状态
持久状态是单元测试的敌人。让单元测试有效的事情之一便是每个测试必须独立于其他所有测试。如果不是这样,那么测试运行的顺序会影响到测试的结果。这可能会导致测试在不应该失败的地方失败,甚至更坏的事情是仅仅因为测试的运行顺序导致测试通过。这可能会隐藏住bugs并且是邪恶的。防止状态从一个测试携带到另一个测试的一个很好办法便是避免使用静态变量。单例模式,就其本质而言,依赖于在一个静态变量中保存着一个实例。这是测试依赖的一个挑战,可以通过传递对象的引用到你的类和方法中来避免。
希望这篇文章或多或少地阐释了我对于单例模式观点。我有一个从google或者其他地方找到的一个小链接集,包括Jim Hyslop和Herb Sutter,他们同样分享了这些观点。如果你喜欢他们那么让我知道吧。
更多文章请关注我的个人博客:http://www.nomoneynowife.com