单身设计模式:陷阱

目前我对这种“设计模式”非常感兴趣。 我不确定是否有使用这种严格的全局状态实施的垮台。 那么,你认为什么时候不在应用程序中练习单例?

如果您正在进行unit testing,单身通常是一个坏主意,而且通常不做unit testing(或BDD或验收测试)也是一个坏主意。

使对象具有全局状态意味着涉及这些对象的unit testing将被隔离并且彼此不相交。 相反,你将不得不担心重置每个测试的状态,并相信我……这是100%的时间永远不会完成。 如果您没有重置全局状态,那么您开始变得非常奇怪并且很难在您的测试中调试浪费时间的错误。

全局状态还会增加代码中的耦合并使重构变得非常困难。

理想的方法是使用IoC / DI容器(Spring,Guice等)来请求对象。 这些容器通常有使对象显示为“单身人士”的方法,但他们也有办法根据情况修改该行为(即unit testing与域代码)。

这一切都取决于你的问题的大小当然。 如果你正在一起攻击一个4级试验台试图解决问题,那么继续使用Singleton。 然而,一旦该项目延续生命并且变得越来越大,越来越复杂,那么将Singleton重构出来。

谷歌技术会谈前段时间有关于全球州和单身人士的精彩演讲。 静态单例模式是邪恶的,因为它会导致不必要的副作用并使代码不可测试。 静态单例是全局变量的OO版本。

解决方案是只创建一个对象实例 ,并通过dependency injection将其传递给用户。 DI框架,例如Guice ,可以很容易地定义好的单例(在Guice中只用@Singleton注释一个类)。 有一个类似的技术讲座叫做“ 不要找东西! 更多地讨论了DI。

除了其他post中提到的测试和设计问题,单身人士和类加载器也存在问题。 单身人士并不是每个JVM或应用程序真正“单一” – 他们通过静态属性实现这一点,这实际上意味着每个类都有一个。 如果有多个类加载器 – 就像在大多数应用服务器中一样 – 每个单独的应用程序都会获得一个新的类加载器,甚至在EJB中使用多个级别的类加载器。 每个类加载器加载一个单例实例 – 这取决于您对单例执行的操作,可能无法生成您期望的结果。

我很少会使用Singleton。 由于它们的性质(静态,全局对象),它们很难用于unit testing代码。 您最终需要进行一些同步或构建一些重新初始化机制,以便为每个unit testing获得一个新版本。 有些情况是有道理的 – 例如,全球配置类 – 但它们比单身人士似乎相信的人要少得多。 我知道我经历了一个阶段,在那里我看到了单例模式的应用。 现在我尽可能地避免它,并通过在我的代码中重构来解除它,因为我遇到了不必要的实现。