为什么在 Java 代码中实现单例模式(有时)被认为是 Java 世界中的反模式?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11292109/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why implementing a Singleton pattern in Java code is (sometimes) considered an anti-pattern in Java world?
提问by Inquisitive
I have seen some people in SO commenting that Singleton Pattern is an anti-pattern. I want to know why ?
我在 SO 中看到一些人评论单例模式是一种反模式。我想知道为什么?
回答by Brian Agnew
Testing
测试
One reason is that singletons aren't easy to handle with unit tests. You can't control the instantiation and by their very nature may retain state across invocations.
原因之一是单例不容易通过单元测试处理。您无法控制实例化,并且就其本质而言,可能会在调用之间保留状态。
For that reason the principle of dependency injectionis popular. Each class is injected (configured) with the classes they need to function (rather than derive via singleton accessors) and so tests can control which dependent class instances to use (and provide mocks if required).
出于这个原因,依赖注入的原则很受欢迎。每个类都注入(配置)了它们需要运行的类(而不是通过单例访问器派生),因此测试可以控制要使用的依赖类实例(并在需要时提供模拟)。
Frameworks such as Spring will control the lifecycle of their objects and often create singletons, but these objects are injected into their dependent objects by the framework. Thus the codebase itself doesn't treat the objects as singletons.
Spring等框架会控制自己对象的生命周期,经常会创建单例,但是这些对象是被框架注入到它们依赖的对象中的。因此,代码库本身不会将对象视为单例。
e.g. rather than this (for example)
例如而不是这个(例如)
public class Portfolio {
private Calculator calc = Calculator.getCalculator();
}
you would inject the calculator:
你会注入计算器:
public class Portfolio {
public Portfolio(Calculator c) {
this.calc = c;
}
}
Thus the Portfolio
object doesn't know/care about how many instances of the Calculator
exist. Tests can inject a dummy Calculator
that make testing easy.
因此,Portfolio
对象不知道/关心Calculator
存在的实例数量。测试可以注入一个Calculator
使测试变得容易的假人。
Concurrency
并发
By limiting yourself to one instance of an object, the options for threading are limited. Access to the singleton object may have to be guarded (e.g. via synchronisation). If you can maintain multiple instances of those objects, then you can tailor then number of instances to the threads you have running, and increase the concurrent capabilities of your codebase.
通过将自己限制为对象的一个实例,线程化的选项是有限的。可能必须保护对单例对象的访问(例如,通过同步)。如果您可以维护这些对象的多个实例,那么您可以根据正在运行的线程定制实例数量,并增加代码库的并发能力。
回答by MikePatel
My personal opinion is that it violates the single responsibility principle. Singleton objects are responsible for both their purpose and controlling the number of instances they produce which I think is wrong.
我个人的看法是它违反了单一职责原则。单例对象负责它们的目的和控制它们产生的实例数量,我认为这是错误的。
This is why a lot of people delegate the control to a factory object.
这就是为什么很多人将控制权委托给工厂对象的原因。
回答by Tom Hawtin - tackline
[Mutable] Singleton is an anti-pattern of an anti-pattern.
[可变] Singleton 是反模式的反模式。
The significant underlying anti-pattern is global state (or ambient state). With global state you have a big blog of dependency across your program. This does affect testing, but that's just a one part of the fallout from bad programming.
重要的底层反模式是全局状态(或环境状态)。有了全局状态,你的程序就有了一个很大的依赖博客。这确实会影响测试,但这只是不良编程后果的一部分。
Layered upon that, Singleton adds completely unnecessary level of complexity over simply declaring mutable static
fields.
在此基础上,Singleton 比简单地声明可变static
字段增加了完全不必要的复杂程度。
回答by Damon
Singletons as such are not necessarily an anti-pattern, but they have only few benefits and become an antipattern when they are used wrong (which happens often).
这样的单例不一定是反模式,但它们只有很少的好处,并且在错误使用时会成为反模式(这种情况经常发生)。
Often, singletons are not singletons at all, but "global variables in disguise". Also, often they are used when the "only one instance" property is actually not an advantage. (which again is balanced by the fact that many times the implementation is wrong at the same time).
通常,单身人士根本不是单身人士,而是“伪装的全局变量”。此外,当“只有一个实例”属性实际上不是优势时,通常会使用它们。(这又被多次执行同时错误的事实所平衡)。
In addition to that, they can be tricky to implement with multithreading in mind (often done wrong or inefficiently), and they lose most of their benefits if you want to control their instantiation.
除此之外,考虑到多线程实现它们可能很棘手(通常做错了或效率低下),如果你想控制它们的实例化,它们将失去大部分好处。
If you want to have control over instantiation, you need to do it by hand at some point early in the program, but then you could just as well just create one instance of a normal object and pass that onward.
If order of destruction is of any concern, you need to manually implement this as well. A single automatic object in the main function is just so much cleaner and easier.
如果你想控制实例化,你需要在程序早期的某个时候手动完成,但是你也可以只创建一个普通对象的实例并继续传递。
如果销毁顺序有任何问题,您也需要手动实现它。主函数中的单个自动对象更简洁、更容易。
回答by Marko Topolnik
There are many requirements that you might have on the singleton:
您可能对单身人士有许多要求:
- lazy initialization;
- proper disposal;
- scoping (one per thread, for example).
- 延迟初始化;
- 妥善处置;
- 范围(例如,每个线程一个)。
Typically, also, you'll have a whole lot of singletons in your app, and the Singletonpattern doesn't allow reusable code. So, if you want to implement all these concerns for all your singletons, you'll immediately see its anti-patternquality.
通常,您的应用程序中也会有很多单例,而单例模式不允许可重用的代码。所以,如果你想为所有的单身人士实现所有这些问题,你会立即看到它的反模式质量。
回答by Fred
Strange. It seems that the incorrect implementation of a Singleton is an "anti-pattern", not the Singleton itself.
奇怪的。单例的错误实现似乎是一种“反模式”,而不是单例本身。
I think we've forgotten that every program has to start somewhere. There has to be a concrete implementation of every abstraction, and eventually every dependency will eventually be resolved, or your app wouldn't be much use.
我想我们已经忘记了每个程序都必须从某个地方开始。每一个抽象都必须有一个具体的实现,最终每个依赖最终都会得到解决,否则你的应用程序将没有多大用处。
Most DI frameworks allow instantiating a class as a Singleton, it just handles that for you. If you choose to do DI yourself, injecting a singleton isn't a problem. A Singleton IS testable as well, and if you're using DI to inject it, doesn't make a class unstable.
大多数 DI 框架允许将类实例化为单例,它只是为您处理。如果你选择自己做 DI,注入单例不是问题。Singleton 也是可测试的,如果您使用 DI 注入它,不会使类变得不稳定。
IMO, like every other pattern out there (including DI and IoC) it's a tool. Sometimes it fits, sometimes it doesn't.
IMO,就像所有其他模式(包括 DI 和 IoC)一样,它是一种工具。有时适合,有时不适合。