by Miško Hevery
Since I have gotten lots of love/hate mail on the Singletons are Pathological Liars and Where Have All the Singletons Gone I feel obliged to to do some root cause analysis.
Lets get the definition right. There is Singleton the design pattern (Notice the capital "S" as in name of something) and there is a singleton as in one of something (notice the lower case "s"). There is nothing wrong with having a single instance of a class, lots of reasons why you may want to do that. However, when I complain about the Singletons, I complain about the design pattern. Specifically: (1) private constructor and (2) global instance variable which refers to the singleton. So from now on when I say Singleton, I mean the design (anti)pattern.
I would say that at this point most developers recognize that global state is harmful to your application design. Singletons have global instance variable which points to the singleton. The instance is global. The trouble with global variables is that they are transitive. It is not just the global variable marked with static which is global but any other variable/object which is reachable by traversing the object graph. All of it is global! Singletons, usually are complex objects which contain a lot of state. As a result all of the state of Singleton is global as well. I like to say that "Singletons are global state in sheep's clothing." Most developers agree that global state is bad, but they love their Singletons.
The moment you traverse a global variable your API lies about its true dependencies (see: Singletons are Pathological Liars) The root problem is not the Singleton design pattern, the root problem here is the global reference to singleton. But the moment you get rid of the global variable you get rid of the Singleton design pattern. So from my point of view blaming Singletons or blaming global state is one and the same. You can't have a Singleton design pattern and at the same time not have the global state.
Someone pointed out that any design pattern can be abused. I agree, but with Singleton design pattern, I don't know how I can possibly use it in a good way. The global reference and hence the global state is ever so present. Now, in my line of work I don't see too much global state in classical sense of the word, but I see a lot of global state masquerading as Singletons. Hence, I complain about Singletons. If I would complain about global state no one would care, as that is old news.
Now, there is one kind of Singleton which is OK. That is a singleton where all of the reachable objects are immutable. If all objects are immutable than Singleton has no global state, as everything is constant. But it is so easy to turn this kind of singleton into mutable one, it is very slippery slope. Therefore, I am against these Singletons too, not because they are bad, but because it is very easy for them to go bad. (As a side note Java enumeration are just these kind of singletons. As long as you don't put state into your enumeration you are OK, so please don't.)
The other kind of Singletons, which are semi-acceptable are those which don't effect the execution of your code, They have no "side effects". Logging is perfect example. It is loaded with Singletons and global state. It is acceptable (as in it will not hurt you) because your application does not behave any different whether or not a given logger is enabled. The information here flows one way: From your application into the logger. Even thought loggers are global state since no information flows from loggers into your application, loggers are acceptable. You should still inject your logger if you want your test to assert that something is getting logged, but in general Loggers are not harmful despite being full of state.
So the root cause is "GLOBAL STATE!" Keep in mind that global state is transitive, so any object which is reachable from a global variable is global as well. It is not possible to have a Singleton and not have a global state. Therefore, Singleton design patter can not be used in "the right way." Now you could have a immutable singleton, but outside of limited use as enumerations, they have little value. Most applications are full of Singletons which have lots of global state, and where the information flows both directions.
10 comments:
what's your take on Spring transaction manager (http://static.springframework.org/spring/docs/2.5.x/reference/transaction.html ) ? no good, huh ?
I think "Singletons considered harmful" is just a short way off now :-)
So how would one go about getting rid of Singletons? I use them for stuff that, well, only needs 1 instance. I would have to pass a non-singleton through to the method or function that needs it. Typically the reference would end up getting passed through several classes and calls. A Singleton short circuits that by popping up right were it is needed. e.g. a simple example:
class B {
void doMoreStuff() {
C::instance().setSomething();
}
}
class A {
void doStuff() {
b->doMoreStuff();
}
}
int main() {
A a;
a.doStuff();
}
Typically if A is the runner or controlling class, there's only 1 of it anyway, created in the main(). So adding a C instance member variable to A means you would have to pass it in everywhere that needed to use it. i.e. after de-singletonising:
class B {
void doMoreStuff(C *c) {
c->setSomething();
}
}
class A {
A(): c_(new C) {}
void doStuff() {
b->doMoreStuff(c_);
}
C *c_;
}
int main() {
A a;
a.doStuff();
}
Or create all the singletons in main() and inject them into the A instance's constructor with a factory. But in the end the no-longer-a-singleton has to get to where it's used, and that can be a real pain. Singletons make life easier in these cases; a guilty pleasure! I think the answer to "what can be done?" will inevitably be "it depends".
@Quirky
having a singleton directly where you needs it without having to pass it thru many layers is indeed really seductive.
From my experience, it only prooves that you have a bad architecture to begin with.
Sometimes the architecture is something you can't change, so singleton may have some use there.
But mark my words, singleton are nasty boomerangs, they will come back in your face at full speed.
I have never seen a Singleton survive in big code base focused on quality, in the long run, they are simply to dangerous/painful. They can exist during a period of time, but they are replaced ASAP, before they rigidify the system around them.
For example, singletons and multicore/multiprocesses are really really something you don't want to mix.
No that I disagree that prolific referencing of global data (i.e. abuse of the singleton pattern) leads to brittle / hard to test software ...
The irony here is that the vast majority of IoC containers require heavily on use of the singleton pattern themselves ;)
Think ..
ContextRegistry.GetContext().GetObject("MyType")
in Spring.NET for instance ;)
As you said, I think "most developers recognize" that old-school global variables (like those heavily abused in C) are a blight. But this is really a bit of a nostalgic argument, and I don't know that it's directly relevant to Singletons.
Singletons can certainly be abused, but I'd say they're one step up from C-style global vars. At least they let us categorize global vars and behaviors into classes, to give hints as to purpose and improve serviceability.
I think the core problem really stems from (what is incidentally your primary viewpoint) testability concerns. And from there I can agree with you, and have been reviewing your previous articles for suggestions on how to improve this issue.
Nonetheless, I think it's a mistake to wholly throw out Singletons as remnants of caveman code. They have their place, and they are an improvement over what "most developers" think of as global state.
In my experience, i found singleton pattern useful for ValueObjects (aka immutable objects) or objects witout state. An example is .NET DBNull.Value, string.Empty and CultureInfo.InvariantCulture. You can use/make assertion based on the same instance also on your tests, so:
Assert.AreEqual(DBNull.Value, m_target.Query());
Bye
Let's for the sake of argument say that Singleton is considered harmful. Just as Quirky asked, what can be done? Some concrete tips would be really handy I think.
網頁設計,情趣用品店,情趣用品專賣網
A片,色情A片,免費A片,成人影片,色情影片,a片免費看,情色貼圖,情色文學,情色小說,色情小說
AV,AV女優
辣妹視訊,美女視訊,視訊交友網,視訊聊天室,視訊交友,視訊美女,免費視訊,免費視訊聊天,視訊交友90739,免費視訊聊天室,成人聊天室,視訊聊天,視訊交友aooyy
哈啦聊天室,辣妺視訊,A片,色情A片,視訊,080視訊聊天室,視訊美女34c,視訊情人高雄網,視訊交友高雄網,0204貼圖區,sex520免費影片,情色貼圖,視訊ukiss
wholesale jewelry
handmade jewelry
jewelry wholesale
fashion jewelry
costume jewelry
wholesale costume jewelry
wholesale fashion jewelry
wholesale pearl
wholesale crystal
discount jewelry
cheap jewelry
wholesale gemstone
wholesale swarovski crystal
wholesale shell
wholesale coral
wholesale turquoise
Weekends to people ig2tmean that they can have a two-day wowgold4europe good rest. For example, people [url=http://www.gameusd.org ]gameusd[/url]can go out to enjoy themselves or get meinwowgold together with relatives and friends to talk with each storeingame other or watch interesting video tapes with the speebie whole family.
Everyone spends agamegold weekends in his ownmmofly way. Within two days, some people can relax themselves by listening to music, reading novels, or watching ogeworld films. Others perhaps are more active by playing basketball, wimming or mmorpgvip dancing. Different people have different gamesavor relaxations.
I often spend weekends withoggsale my family or my friends. Sometimes my parents take me on a visit to their old friends. Sometimesgamersell I go to the library to study or borrow some books to mmovirtex gain much knowledge. I also go to see various exhibition to broaden rpg trader my vision. An excursion to seashore or mountain resorts is my favorite way of spending weekends. Weekends are always enjoyable for me.
Post a Comment