我看到有人在评论说Singleton Pattern是一种反模式。我想知道为什么?
答案 0 :(得分:51)
<强>测试强>
一个原因是单身人士在单元测试中不易处理。您无法控制实例化,并且它们本质上可能会在调用期间保持状态。
因此dependency injection的原则很受欢迎。每个类都注入(配置)它们需要运行的类(而不是通过单例访问器派生),因此测试可以控制使用哪些依赖类实例(并在需要时提供模拟)。
Spring等框架将控制对象的生命周期并经常创建单例,但这些对象由框架注入其依赖对象。因此,代码库本身并不将对象视为单例。
e.g。而不是这个(例如)
public class Portfolio {
private Calculator calc = Calculator.getCalculator();
}
你会注入计算器:
public class Portfolio {
public Portfolio(Calculator c) {
this.calc = c;
}
}
因此Portfolio
对象不知道/关心Calculator
存在多少个实例。测试可以注入一个虚拟Calculator
,使测试变得容易。
<强>并发强>
通过将自己限制为对象的一个实例,线程的选项是有限的。可能必须保护对单个对象的访问(例如,通过同步)。如果您可以维护这些对象的多个实例,那么您可以根据已运行的线程定制实例数量,并增加代码库的并发功能。
答案 1 :(得分:22)
我个人认为它违反了单一责任原则。 Singleton对象负责其目的和控制它们产生的实例数,我认为这是错误的。
这就是很多人将控件委托给工厂对象的原因。
答案 2 :(得分:11)
[Mutable] Singleton是一种反模式的反模式。
重要的潜在反模式是全局状态(或环境状态)。在全球范围内,您的整个计划中都有一个很大的依赖博客。这确实会影响测试,但这只是糟糕编程的影响的一部分。
在此基础上,Singleton在简单地声明可变static
字段时添加了完全不必要的复杂程度。
答案 3 :(得分:8)
单身人士不一定是反模式,但他们只有很少的好处,并且当他们被错误使用时会成为反模式(经常发生)。
通常,单身人士根本不是单身人士,而是“伪装的全球变数”。此外,通常在“仅一个实例”属性实际上不具有优势时使用它们。 (再次通过多次同时执行错误的事实来平衡。)
除此之外,考虑到多线程(通常做错了或效率低下)实现它们可能很棘手,如果你想控制它们的实例化,它们就会失去大部分的好处。
如果你想控制实例化,你需要在程序早期的某个时候手工完成,但是你也可以创建一个普通对象的实例并将其传递给它。
如果破坏顺序有任何问题,您也需要手动实现。主要功能中的单个自动对象更加简洁明了。
答案 4 :(得分:7)
单身人士可能有许多要求:
通常情况下,您的应用中也会有很多单例, Singleton 模式不允许使用可重复使用的代码。所以,如果你想为所有单身人士实现所有这些问题,你会立即看到它的反模式质量。
答案 5 :(得分:4)
奇怪。似乎Singleton的错误实现是一种“反模式”,而不是Singleton本身。
我想我们已经忘记了每个程序都必须从某个地方开始。必须有一个每个抽象的具体实现,并最终每个依赖最终将被解决,或者您的应用程序将没有多大用处。
大多数DI框架允许将类实例化为Singleton,它只是为您处理。如果您选择自己做DI,注入单身不是问题。 Singleton IS也是可测试的,如果你使用DI来注入它,不会使类不稳定。
IMO,就像其他所有模式(包括DI和IoC)一样,它是一种工具。有时它适合,有时它不适合。