将光标移到/点击文章中的句子上,可以查看译文。      显示繁体中文内容    显示简体中文内容

What is so bad about singletons?
单例模式的缺点是什么?

The singleton pattern is a fully paid up member of the GoF 's patterns book, but it lately seems rather orphaned by the developer world.i still use quite a lot of singletons, especially for factory classes, and while you have to be a bit careful about multithreading issues (like any class actually), i fail to see why they are so awful.

Stack Overflow especially seems to assume that everyone agrees that Singletons are evil.Why?

时间:

Paraphrased from Brian Button :

  1. They are generally used as a global instance, why is that so bad?because you hide the dependencies of your application in your code, instead of exposing them through the interfaces.Making something global to avoid passing it around is a code smell.

  2. They violate the single responsibility principle :by virtue of the fact that they control their own creation and lifecycle.

  3. They inherently cause code to be tightly coupled.this makes faking them out under test rather difficult in many cases.

  4. They carry state around for the lifetime of the application.another hit to testing since you can end up with a situation where tests need to be ordered which is a big no no for unit tests.Why? because each unit test should be independent from the other.

Singletons solve one (and only one) problem.

Resource Contention.

If you have some resource that

( 1 ) can only have a single instance, and

( 2 ) you need to manage that single instance,

you need a singleton.

There aren't many examples. A log file is the big one.you don't want to just abandon a single log file.you want to flush, sync and close it properly.this is an example of a single shared resource that has to be managed.

It's rare that you need a singleton.the reason they're bad is that they feel like a global and they're a fully paid up member of the GoF Design Patterns book.

When you think you need a global, you're probably making a terrible design mistake.

Misko Hevery, from Google, has some interesting articles on exactly this topic...

Singletons are Pathological Liars has a unit testing example that illustrates how singletons can make it difficult to figure out dependency chains and start or test an application.it is a fairly extreme example of abuse, but the point that he makes is still valid :

Singletons are nothing more than global state.Global state makes it so your objects can secretly get hold of things which are not declared in their APIs, and, as a result, Singletons make your APIs into pathological liars.

where have all the Singletons gone makes the point that dependency injection has made it easy to get instances to constructors that require them, which alleviates the underlying need behind the bad, global Singletons decried in the first article.

One rather bad thing about singletons is that you can't extend them very easily.you basically have to build in some kind of decorator pattern or some such thing if you want to change their behavior.Also, if one day you want to have multiple ways of doing that one thing, it can be rather painful to change, depending on how you lay out your code.

One thing to note, if you do use singletons, try to pass them in to whoever needs them rather than have them access it directly...otherwise if you ever choose to have multiple ways of doing the thing that singleton does, it will be rather difficult to change as each class embeds a dependency if it accesses the singleton directly.

So basically :


public MyConstructor(Singleton singleton) {
 this.singleton = singleton;
}

rather than :


public MyConstructor() {
 this.singleton = Singleton.getInstance();
}

I believe this sort of pattern is called dependency injection and is generally considered a good thing.

Like any pattern though... think about it and consider if its use in the given situation is inappropriate or not...Rules are made to be broken usually, and patterns should not be applied willy nilly without thought.

The singleton pattern is not a problem in itself.the problem is that the pattern is often used by people developing software with object-oriented tools without having a solid grasp of OO concepts.when singletons are introduced in this context they tend to grow into unmanageable classes that contain helper methods for every little use.

Singletons are also a problem from a testing perspective.they tend to make isolated unit-tests difficult to write.Inversion of control (IoC) and dependency injection are patterns meant to overcome this problem in an object-oriented manner that lends itself to unit testing.

In a garbage collected environment singletons can quickly become an issue with regard to memory management.

There is also the multi-threaded scenario where singletons can become a bottleneck as well as a synchronization issue.

Singletons are also bad when it comes to clustering.because then, you do not have"exactly one singleton"in your application anymore.

Consider the following situation : as a developer, you have to create a web application which accesses a database.to ensure that concurrent database calls do not conflict each other, you create a thread-save SingletonDao :


public class SingletonDao {
//songleton's static variable and getInstance() method etc. omitted
 public void writeXYZ(...){
 synchronized(...){
//some database writing operations...
 }
 }
}

So you are sure that only one singleton in your application exists and all database go through this one and only SingletonDao.your production environment now looks like this :Single Singleton

Everything is fine so far.

Now, consider you want to set up multiple instances of your web application in a cluster.Now, you suddenly have something like this :

Many singletons

That sounds weird, but now you have many singletons in your application.and that is exactly what a singleton is not supposed to be :having many objects of it.this is especially bad if you, as shown in this example, want to make synchronized calls to a database.

Of course this is an example of a bad usage of a singleton.but the message of this example is :you can not rely that there is exactly one instance of a singleton in your application - especially when it comes to clustering.

...