我知道单例类是只能有一个实例化的类,但我不明白为什么这会有用。为什么不创建一个包含静态变量和方法的类,并在需要时使用同步来确保没有两个线程同时执行该类中的方法。我只是不明白为什么有人会经历创建这种类的麻烦。我知道我在这里遗漏了一些东西。
谢谢,
I understand that a singleton class is one where there can be only one instantiation, but I don't understand why this would be useful. Why won't you just create a class with static variables and methods and use synchronize if needed to make sure that no two threads were executing a method in the class simultaneously. I just don't get why anyone would go through the trouble of creating this kind of class. I know I'm missing something here.
Thanks,
发布评论
评论(11)
虽然我同意其他答案,但OP问为什么不拥有一个包含所有静态方法(可能包含静态字段)的类,而不是拥有一个实例的单例。
为什么要使用 Singleton?
你可以通过 Google 搜索“singleton”来查找各种原因。来自 JavaWorld:
为什么使用单例而不是具有所有静态方法的类?
几个原因
对于#3,如果您的单例是一个数据库连接池,您希望确保您的应用程序只有一个实例,但对数据库连接池本身进行单元测试而不访问数据库(可能是通过使用包范围构造函数或静态创建方法):(
注意使用 初始化按需持有者 模式)
然后,您可以使用包范围
createInstanceForTest
方法来测试DatabaseConnectionPool
。但请注意,静态
getInstance()
方法可能会导致“静态附着”,其中依赖于单例的代码无法进行单元测试。因此,静态单例通常不被认为是一个好的实践(请参阅这篇博文)相反,您可以使用 Spring 或 Guice 等依赖注入框架来确保您的类在生产中只有一个实例,同时仍然允许使用该类的代码可测试的。由于 Singleton 中的方法不是静态的,因此您可以使用 JMock 之类的模拟框架在测试中模拟您的单例。
While I agree with the other answers, the OP was asking why not have a class with all static methods (possibly with static fields) instead of a singleton where you have one instance.
Why use Singletons?
You can Google "singleton" to find all sorts of reasons. From JavaWorld:
Why use a Singleton instead of a class with all static methods?
A few reasons
For #3, if your Singleton was a database connection pool, you want to insure that your application has only one instance, but do unit testing of the database connection pool itself without hitting the database (possibly by using a package-scope constructor or static creational method):
(notice the use of the Initialization On Demand Holder pattern)
You can then do testing of the
DatabaseConnectionPool
by using the package-scopecreateInstanceForTest
method.Note, however, that having a static
getInstance()
method can cause "static cling", where code that depends on your singleton cannot be unit tested. Static singletons are often not considered a good practice because of this (see this blog post)Instead, you could use a dependency injection framework like Spring or Guice to insure that your class has only one instance in production, while still allowing code that uses the class to be testable. Since the methods in the Singleton aren't static, you could use a mocking framework like JMock to mock your singleton in tests.
仅具有静态方法(和私有构造函数)的类是根本没有实例(0 个实例)的变体。
单例是只有 1 个实例的类。
这些是不同的东西,并且有不同的用例。最重要的是状态。单例通常保护对逻辑上只有一个的事物的访问。例如,应用程序中的屏幕可能由单例表示。创建单例时,将初始化与这一事物的资源和连接。
这与具有静态方法的实用程序类有很大的不同——那里不涉及任何状态。如果存在,您必须(在同步块中)检查状态是否已创建,然后按需(延迟)初始化它。对于某些问题,这确实是一个解决方案,但是您需要为每个方法调用的开销付出代价。
A class with only static methods (and a private contructor) is a variant where there is no instance at all (0 instances).
A singleton is a class for which there is exactly 1 instance.
Those are different things and have different use cases. The most important thing is state. A singleton typically guards access to something of which there is logically only ever one. For instance, -the- screen in an application might be represented by a singleton. When the singleton is created, resources and connections to this one thing are initialized.
This is a big difference with a utility class with static methods - there is no state involved there. If there was, you would have to check (in a synchronized block) if the state was already created and then initialize it on demand (lazily). For some problems this is indeed a solution, but you pay for it in terms of overhead for each method call.
使用单例模式来封装每个应用程序只应创建(初始化)一次的资源。您通常对管理对共享实体(例如数据库)的访问的资源执行此操作。单例可以控制有多少并发线程可以访问该共享资源。即因为有一个数据库连接池,所以它可以控制将多少数据库连接分发给需要它们的线程。记录器是另一个示例,记录器确保可以适当地管理对共享资源(外部文件)的访问。通常,单例还用于加载创建成本昂贵(缓慢)的资源。
您通常会像这样创建一个单例,并在 getInstance 上同步:
但是像这样创建它同样有效,
两种方法都会为 PER 类加载器创建一个实例。
Use the singleton pattern to encapsulate a resource that should only ever be created (initialised) once per application. You usually do this for resources that manage access to a shared entity, such as a database. A singleton can control how many concurrent threads can access that shared resource. i.e. because there is a single database connection pool it can control how many database connections are handed out to those threads that want them. A Logger is another example, whereby the logger ensures that access to the shared resource (an external file) can be managed appropriately. Oftentimes singletons are also used to load resources that are expensive (slow) to create.
You typically create a singleton like so, synchronising on getInstance:
But it is equally valid to create it like so,
Both methods will create a single instance PER classloader.
数据库实例是单例有用的地方,因为一个线程只需要一个数据库连接。我敢打赌,还有很多其他实例,例如数据库连接,您只需要某个实例的一个实例,而这就是您使用单例的地方。
Database instances is one place singletons are useful, since a thread only wants one DB connection. I bet there are a lot of other instances like database connections where you only want one instance of something and this is where you would use a singleton.
对我来说,更喜欢单例而不是具有静态方法的类的原因是可测试性。假设我实际上需要确保某个类确实只有一个实例。我可以使用单例或仅包含静态方法的静态类来做到这一点。我们还可以说,我想在另一个类中使用此类,但出于测试目的,我想模拟第一个类。唯一的方法是将类的实例注入到第二个类中,这要求您有一个非静态类。在测试方面您仍然遇到一些痛苦 - 您可能需要构建一些可以通过反射调用的代码来删除单例以用于测试目的。您还可以使用接口(尽管这将明确允许其他开发人员使用除单例之外的其他内容)并简单地将单例作为接口的实例提供给使用它的类。
For me the reason to prefer singleton over a class with static methods is testability. Let's say that I actually need to ensure that there really is one and only one instance of a class. I could do that with either a singleton or a static class with only static methods. Let's also say that I'd like to use this class in another class, but for testing purposes I'd like to mock the first class out. The only way to do that is to inject an instance of the class into the second class and that requires that you have a non-static class. You still have some pain with respect to testing -- you might need to build in some code you can invoke with reflection to delete the singleton for test purposes. You can also use interfaces (though that would explicitly would allow the use of something other than the singleton by another developer) and simply provide the singleton as an instance of the interface to the class that uses it.
一个考虑因素是使单例成为实例允许您实现接口。仅仅因为您想要控制它的实例化,并不意味着您希望每段代码都知道它是单例。
例如,假设您有一个创建数据库连接的连接提供程序单例。
如果它是一个具有静态方法的类,则无法注入依赖项,如下所示:
如果您稍后想要对您的方法进行单元测试(您可以传入一个模拟的连接提供程序),则依赖项注入很有用
(您可以传入一个模拟的连接提供程序)其他事情。
One consideration is that making a singleton an instance allows you to implement an interface. Just because you want to control instantiation to it, does not mean you want every piece of code to know that it's a singleton.
For example, imagine you had a connection provider singleton that creates DB connections.
If it were a class with static methods, you couldn't inject the dependency, like this:
It would have to be
Dependency injection is useful if you later want to unit test your method (you could pass in a mocked connection provider instead) among other things.
单例比具有静态变量和方法的类具有优势:它是一个对象实例,可以从类继承(例如:具有单个主体 JFrame 的应用程序),并扩展一个或多个接口(因此被视为实现这些接口的任何其他对象)。
A singleton has the advantatage over a class with static variables and methods : it's an object instance, which can inherit from a class (example : an application that ahas a single principal JFrame), and extend one or more interfaces (and thus be treated as any other object implementing these interfaces).
有些人认为单例是无用且危险的。 我不完全同意,但是关于它的一些观点是有效的,并且应该谨慎使用单例。
在我看来,用静态类代替单例更糟糕。静态类主要用于对不共享公共资源的相关函数进行分组。
java.util.Collections
就是一个很好的例子。它只是一堆不绑定到任何对象的函数。另一方面,单例是真正的对象。理想情况下,单例应该在不考虑单例模式的情况下实现。如果您突然需要它,这将使您可以轻松切换到使用多个实例。例如,您可能只有一个数据库连接,但随后您必须同时使用另一个完全不相关的数据库。你只需将你的单例变成“双例”或“三例”或其他什么。如果需要,您还可以将其构造函数公开,这将允许创建任意数量的实例。所有这些东西用静态类实现并不那么容易。
简而言之,单例是一种常规类,它有一个全局可用的实例,这样您就可以免去将其作为参数传递到任何地方的麻烦。
而且创建单例也没有太大的麻烦。您只需创建一个带有私有构造函数的常规类,然后实现一个工厂方法,就完成了。
Some people think that singletons are useless and dangerous. I don't completely agree, but some points about it are valid, and singletons should be used carefully.
Static classes used in place of singletons are even worse in my opinion. Static classes should be mainly used to group related functions which don't share a common resource.
java.util.Collections
is a good example. It's just a bunch of functions that aren't tied to any object.Singletons, on the other hand, are true objects. Ideally, singleton should be implemented without singleton pattern in mind. This will allow you to easily switch to using multiple instances if you suddenly need it. For example, you may have only one database connection, but then you have to work with another, completely unrelated database at the same time. You just turn your singleton into a "doubleton" or "tripleton" or whatever. If you need, you can also make its constructor public which will allow creation of as many instances as you want. All this stuff isn't so easy to implement with static classes.
Simply put, a singleton is a regular class that has one instance globally available, to save you from all the trouble of passing it everywhere as a parameter.
And there is not much trouble in creating a singleton. You just create a regular class with a private constructor, then implement one factory method, and you're done.
您什么时候需要使用它?
有许多对象我们只需要其中之一:线程池、缓存、对话框、处理首选项和注册表设置的对象、用于日志记录的对象以及充当打印机和显卡等设备的设备驱动程序的对象。对于许多此类对象,如果我们要实例化多个对象,我们将遇到各种问题,例如不正确的程序行为或过度使用资源。
关于同步的使用,它绝对是昂贵的,也是唯一的时间同步与第一次或唯一实例化相关,一旦实例化,我们就不再需要再次同步。第一次通过后,同步是完全不需要的开销:(
When would you need to use one?
There are many objects we only need one of: thread pools, caches, dialog boxes, objects that handle preferences and registry settings, objects used for logging, and objects that act as device drivers to devices like printers and graphic cards. For many of these types of object if we were to intantiate more than one we would run intol all sorts of problems like incorrect program behavior or overuse of resources
Regarding the usage of synchronization it is definitly expensive and the only time syncrhonization is relevant is for the first time or the unique instatiation once instantiated we have no further need to synchronize again. After the first time through, syncrhonization is totally unneeded overhead :(
在我回复时其他人提供了更好的答案,但我会将我的答案留给后代。看来单元测试是这里的一大推动力。
出于所有意图和目的,没有理由比您描述的方法更喜欢单例。有人认为静态变量是大写 b 不好的(就像其他有时有用的功能,如 goto),因为它们离全局数据不远,作为响应,我们有单例的解决方法。
Others have provided better answers while I was replying, but I'll leave my answer for posterity. It would appear unit testing is the big motivator here.
For all intents and purposes, there is no reason to prefer a singleton to the approach you described. Someone decided that static variables are capital-b Bad (like other sometimes useful features like gotos) because they're not far off from global data and in response we have the workaround of singletons.
它们也与其他图案一起使用。请参阅 可观察类是否可以构造为单例?
They are also used with other patterns. See Can an observable class be constructed as a singleton?