Singleton Design Pattern: Pitfalls
目前我对这个"设计模式"非常感兴趣。不过,我不确定使用这种严格的全局状态实现是否会出现故障。那么,您认为什么时候不在应用程序中练习单例呢?
如果您正在进行单元测试,单例通常是一个坏主意,而不进行单元测试(或BDD或验收测试)通常是一个坏主意。
使对象具有全局状态意味着您所编写的涉及这些对象的单元测试将相互隔离和分离。相反,您将不得不担心重新设置每个测试的状态,相信我……这是从来没有做到100%的时间。如果不重置全局状态,那么测试中的错误就会变得非常奇怪和难以调试,这会浪费时间。
全局状态还增加了代码中的耦合,使得重构非常困难。
理想的方法是使用IOC/DI容器(Spring、Guice等)请求对象。这些容器通常有使对象显示为"单例"的方法,但它们也有根据情况修改该行为的方法(即单元测试与域代码)。
当然,这完全取决于你的问题的大小。如果你正在设计一个4级的测试平台来尝试一些东西,那么就继续使用单件测试吧。然而,一旦这个项目开始了生命,并且变得越来越大和复杂,那么就将单例重构出来。
一段时间前,谷歌的技术谈判就有了一个关于全球国家和单身人士的精彩演讲。静态单例模式是邪恶的,因为它会导致不必要的副作用,并使代码不稳定。静态单例是全局变量的OO版本。
解决方案是只创建对象的一个实例,并通过依赖注入将其传递给用户。DI框架(如guice)使定义好的单例变得容易(guice只是用@singleton注释一个类)。有一个类似的技术谈话叫做不要找东西!这就进一步讨论了DI。
除了在其他文章中提到的测试和设计问题外,还有单例和类装入器的问题。单例不是每个JVM或应用程序真正的"单例"——它们通过静态属性来实现这一点,这实际上意味着每个类都有一个。如果有多个类加载器(就像在大多数应用服务器中一样),每个单独的应用程序都会得到一个新的类加载器,甚至在EJB中也会使用多个级别的类加载器。每个类加载器加载一个单例实例——这取决于您对单例所做的操作,可能不会产生您期望的结果。
我很少用单件的。由于它们的性质(静态、全局对象),在单元测试代码时很难使用它们。您最终需要执行一些同步或构建一些重新初始化机制,以便可以为每个单元测试获得新的版本。有些情况是有意义的——比如说,一个全局配置类——但是它们比刚接触到singleton的人所相信的要少得多。我知道我经历了一个阶段,在这个阶段我到处都看到了单例模式的应用程序。现在,我尽量避免使用它,当遇到不必要的实现时,通过代码中的重构来撤消它。