48

Possible Duplicate:
What is so bad about Singletons?

It's understandable that many design patterns can in some cases be abused, and like mom always said: "Too much of a good thing isn't always good!"

I'm noticing that these days, I'm using Singletons a lot, and I'm worried that I might be abusing the design pattern myself, and running deeper and deeper into a bad-practice kind of habit.

We're developing a Flex application that has a quite a large hierarchical data structure kept in memory while the user works on it. The user can load, save, change and refresh the data on demand.

This data is centralized by means of a Singleton class, which aggregates a couple of ArrayCollections, Arrays, value objects and some other native member variables exposed via getters and setters.

To get a reference to our data from anywhere in the application, we do the whole Model.getInstance() method type of thing, that I'm sure everyone is familiar with. This ensures that we always get our hands on the same copy of data, since when we designed, we said that only once instance is allowed to exist during the application lifetime.

From this central data repository, it's then easy for us to for example, dispatch property changed events, and can have multiple UI components that reference the central data, update their displays to reflect the data changes that have occurred.

So far, this approach has been effective and proven very practical to our circumstances.

I'm finding however, that I'm a little overeager when creating new classes. Questions like should a class be a Singleton, or should it rather be managed some other way, like maybe using a factory for example, tend to sometimes become a bit difficult, with a bit of uncertainty.

Where do I draw the line with singletons? Is there a good guideline for deciding when to use Singletons and when to stay away from them.

Also, can anyone recommend a good book on design patterns?


  • There are a number of similar questions to this, but I'm not really sure if any of them could be considered "exact duplicates"... - Zifre
  • 3 people recommending the same book in under 5 minutes must be a record. And a hint :-) - Stu
  • the problem, on any case, is the excess (ab-use) - BlackTigerX
  • my $0.02 is that in Flex, most solid design principles go out the window because of the stupid hoops you're forced to jump through. I point you to the HierarchicalCollectionView interface for a prime example... - rmeador

12 답변


35

The key thing to remember is that design patterns are just a tool to help you understand the abstract concepts. Once you have that understanding, restricting yourself specifically to a "recipe" from a book is pointless and hurts your ability to write the code most appropriate for your purpose.

That said, reading books like GoF will present you with more ways to think about problems so that when the time comes to implement something on your own, you'll have a wider set of perspectives to approach the problem from.

In your case, if using singleton makes sense in every case, then go right ahead. If it "sort of" fits and you have to implement it in some clunky way, then you need to come up with a new solution. Forcing a pattern that isn't perfect is somewhat like hammering a square peg in a round hole.

Given that you say "this approach has been effective and proven very practical to our circumstances," I think you're doing fine.

Here are some good books:

Gang of Four Book - the classic book for design patterns

Head First Design Patterns - I've heard this recommended by a few people as an alternative


  • Thank you all so much!!! I'll definitely get a copy of at all these books, and work my way through them. I think I've heard about the "Gang of Four Book" somewhere. - josef.van.niekerk
  • Most of the rest of the GoF book is fine, but on the subject of singletons, I seriously think they must have been smoking something illegal. Either that, or it was a concession to old procedural programmers (who really want their globals), in order to win them over to OOP ("Hey look, you can make globals in OOP too! We just call them singletons") - jalf
  • Yeah, I'll second what jalf says, beware of using singletons as just a oop version of global variables. - Simon P Stevens
  • Singleton is always a sign of non-reenterable code, in most cases it is also a sign of untestable code. Their existence can only be justified with faster time to market when maintenance aspect is not of a concern. Even logger, classically considered a valid singleton usecase in C++ may cause the application to crash when a class is logging from the destructor and singleton logger is already gone. - bobah

108

Yes, singletons are bad. They are bad because all they do for you is combine two properties, each of which is bad about 95% of the time. (Which would mean that on average, singletons are bad 99.75% of the time ;))

A singleton, as defined by the GoF, is a data structure which:

  1. Grants global access to an object, and
  2. Enforces that only one instance of the object can ever exist.

The first is generally considered a bad thing. We don't like globals. The second is a bit more subtle, but generally, there are virtually no cases where this is a reasonable restriction to enforce.

Sometimes, it only makes sense to have one instance of an object. In which case you choose to create only one. You don't need a singleton to enforce it.

And usually, even when it "makes sense" to have only one instance, it turns out not to make sense after all. Sooner or later, you're going to need more than one logger. Or more than one database. Or you're going to have to recreate resources for each of your unit tests, which means we have to be able to create them at will. It is prematurely removing flexibility from our code, before we understand the consequences.

Singletons hide dependencies and increase coupling (every class can potentially depend on a singleton, which means the class can not be reused in other projects unless we also reuse all our singletons), and because these dependencies are not immediately visible (as function/constructor parameters), we don't notice them, and typically don't think about it when we create them. It's so easy to just pull in a singleton, it acts almost as a local variable and all, so we tend to use them a lot once they're there. And that makes them almost impossible to remove again. You end up, perhaps not with spaghetti code, but with spaghetti dependency graphs. And sooner or later, your runaway dependencies will mean that singletons start depending on each others, and then you get circular dependencies when one is attempted initialized.

They make it extremely hard to unit-test. (How do you test a function that calls functions on a singleton object? We don't want the actual singleton code to be exercised, but how do we prevent that?

Yes, singletons are bad.

Sometimes, you really want a global. Then use a global, not a singleton.

Sometimes, very very very rarely, you may have a situation where creating multiple instance of a class is an error, where it can not be done without causing errors. (About the only case I can think of, and even that is contrived, is if you're representing some hardware device. You only have one GPU, so if you're going to map it to an object in your code, it would make sense that only one instance can exist). But if you find yourself in such a situation (and again, for emphasis, a situation where multiple instances cause serious errors, not just a situation where "I can't think of any use cases for more than one instance"), then enforce that constraint, but do it without also making the object globally visible.

Each of these two properties can be useful, in rare cases. But I can't think of a single case where the combination of them would be a good thing.

Unfortunately, a lot of people have got the idea that "Singletons are OOP-compliant globals." No, they're not. They still suffer the same problems as globals, in addition to introducing some other, completely unrelated ones. There is absolutely no reason to prefer a singleton over a plain old global.


  • There are tons of times when enforcing a singleton is a critical idea. Think of a database connection pool. You wouldn't want two separate pools, as you would possibly open connections when there may be some already available. - Kekoa
  • Why wouldn't I want two separate pools in my unit tests? Why wouldn't I want two separate pools for separate databases? Why wouldn't I want two separate pools if I have two separate tasks that shouldn't be allowed to starve out each other? One task might hog all the connections in its own pool, so I want to reserve some for the other. But even if you do absolutely positively want only one pool, why do you need a singleton to enforce it? Do you often accidentally create new connection pools? Of course not. If you only need one, just create one. - jalf
  • +1 Couldn't have said it better. Exactly how I feel and educate my fellow colleagues. Many points also apply to the monostate pattern and (ab)use of global static methods. - gix
  • Issue 1 is the real killer, because it is so hard to fix once you have sprinkled it all over your code. - starblue
  • @user The other side is that your coworkers common sense is probably just as good as yours. You wrote the object intending for one instance to exist. He created a second instance. Who are you to say that he is wrong? He encountered a situation where it made sense to create a second instance, that you hadn't anticipated. If it had been a singleton then your coworker would have been unable to do what he thought made sense. My argument is that "should a second instance exist?" is a decision that can only reasonably be made when the class is used, not when it was originally designed. - jalf

14

Software developers seem to be pretty evenly split into two camps, depending on whether they favor an idealistic coding style or a pragmatic one:

  • Idealistic: Never use the singleton pattern.
  • Pragmatic: Avoid the singleton pattern.

Personally, I favor the pragmatic approach. Sometimes it makes sense to break the rules, but only if you really understand what you are doing and are willing to accept the associated risks. If you can answer "yes" to the questions below regarding your specific use case, the singleton pattern can yield some practical benefits.

  • Is the singleton external to your app? Databases, queuing services, and ESBs are all perfectly valid macro examples of the singleton pattern.
  • KISS: Is you entire app limited to 2-3 internal singletons?
  • DRY: Are those singletons inherently global and would therefore result in having to plumb references into almost every object in your app? (e.g., a logger or component mediator)?
  • Do your singletons depend only on each other, and/or the operating environment?
  • Have you ensured proper start-up and shut-down sequences for each singleton, including memory management considerations? For example, a "Grand Central"-style thread pool may need to have instance Run() and Shutdown() methods in main() so that tasks are guaranteed to run only when the objects they operate on are in a valid state.


  • Nice way to make your singleton-addiction more socially acceptable. "I avoid them, I only use them where it makes sense". No you don't. From your own description, you use them all over the place, any time the alternative would require just a small amount of work. The distinction isn't between "idealistic" and "pragmatic", but between those who actually try to avoid singletons (I don't need a singleton for my database connection, for example), and those who say they "avoid" them, when really they just mean "I use them when I think it's the right thing to do" - jalf
  • @jalf The point is to keep an open mind, remain educated on what singletons are good at and what they are bad at, and to then pick the right tool for the task at hand. My philosophy is that any developer can use any design pattern so long as they can sufficiently defend it. Like how in the C# world, it's considered smelly to use things like unsafe and goto in the vast majority of cases, yet both of them are semi-frequently used in the source code of .NET itself. If you know the pros and cons of all options and still decide to use singletons, then that's perfectly fine. - Abion47
  • Nothing sets off red flags in my mind of a developer's capabilities and mindset quite like hearing that something should never be done, period, end of discussion. To me, that just says the developer is locked into a certain way of thinking, and it makes me concerned that they aren't going to be flexible enough to keep up with the competitive and ever-evolving world of software development. I've heard too many stories of people who ruled their development teams with an iron fist using antiquated technologies and conventions while quashing any discussion of change without even consideration. - Abion47

9

Singletons don't kill programs, programmers kill programs.

Like any programming construct, when used appropriately, you will not shoot yourself in the foot.

The books recommended are fine, but they don't always give enough background that comes with experience on when you might make the choice to use Singleton.

That experience only comes when you've found Singleton is a bad choice when you need to have multiple instances, and all of a sudden, you've got a lot of trouble injecting the object references everywhere.

Sometimes it's better to go ahead and have the object references in place, but the fact that you are using Singleton at all does help to identify the scope of the problem you would face if you had to refactor it to a different design. Which I believe is a very good thing: i.e. just having a class at all (even if poorly designed) gives some ability to see the effects of a change to the class.


4

We have started a project where we are basically facing the same question, that is, how to access the model, and especially its root element. The project is not a Flex app, but a play! web app, but that doesn't matter really.

Having a single object unique in the system is fine, the problem is how to access it. So the debate about singleton is related to the notion of dependency injection (DI), and how to obtain objects.

The main arguments for DI are the following:

  • testability and mocking
  • decoupling object instantiation from usage (which can lead to lifecycle management)
  • separation of concerns

Possible approaches for DI are (see the classic article from Fowler):

  • to pass object around in method parameters
  • service locator
  • DI framework

Under this perspective, the singleton pattern is just a kind of service locator, e.g. Model.getInstance().

But to provide maximum flexibility in face of future changes, the reference to the unique object should be passed around as much as possible, and obtained with Model.getInstance() only when necessary. This will also yield cleaner code.


  • Don't you end up with a lot of extra plumbing to support passing the references around? - kgriffs
  • ...especially for something virtually every single component/class is going to use, such as logging? - kgriffs

3

In my opinion the use of Singletons directly signals a design flaw. The reason is simply that they allow one to bypass the normal object creation and destruction mechanisms built into C++. If an object needs a reference to another object, it should either pass in a reference to it upon construction or create a new instance of it internally. But when you use a singleton you're explicitly obfuscating the creation and teardown cycle. A related problem is that it is extremely difficult to control the lifetime of a singleton. As a result, many packages which include generic singleton implementations also include clunky object lifetime managers and the like. Sometimes I wonder if these don't exist simply to manage the singletons.

Basically, if you need to use an object in many places, it should be created explicitly at the highest common point in the stack and then passed down via reference to everybody who uses it. Sometimes people use Singletons because they have problems passing multiple args to new threads, but don't fall for this, explicitly define your thread args and pass them to the new thread in the same manner. You'll find that your program flows much cleaner and there are no nasty surprises due to static initialization dependencies or erroneous teardown.


2

Singletons are certainly not bad. They have their uses, some of them very good. Singletons do tend to be overused by inexperienced developers as it's often the first design patten they learn about, and it's fairly simple, so they chuck it around all over the place without thinking about the implications.

Every time you want to use a singleton, try to consider why you are doing it, and what are the benefits and negatives of using this pattern.

Singletons do effectively create a global accessible set of 'stuff' (either data or methods) and I think most people would agree that using too many global variables is not a great idea. The whole point of classes and object orientation is to group things into discrete areas rather than just chucking everything into one massive global space.

One of the 'patterns' I find I tend to prefer over singletons is to pass needed objects down from the top. I create them once during my apps initialization phase, and a pass them down through all the objects that need access to them. It mimics the 'single-creation' part of a singleton pattern, but without the 'global' part.

The whole point of a singleton is that it's for objects where only 1 should ever exist. You mention a data control set of classes. Perhaps consider that actually, there are cases where an app might want to create 2 sets of data control classes, so perhaps enforcing a singleton on this isn't quite right. Instead, if you created these data classes on app init, and passed them down, you would be only creating 1 set as that is what you current app requires, but you leave open the possibility that at some point, if you need a second set you can easily create them. Also, should data control classes really be accessibly globaly from anywhere in the app. I think not, instead they should probably be only accessible from a lower level data access layer.

Some people have recommended the GOF book. I would say, yes that is a great book, but first try and find a book on general architecture first, read about 2/3/n-tier design, encapsulation, abstraction, and these kind of principles first. This will give you a more solid base with which to understand the appropriate usage of the patterns the GOF talk about.

[Edit: The other time that a singleton variant can be useful is when you want a single access point to something, but the implementation detail might actually be more than one thing. The caller doesn't need to know, that under the covers their request for the singleton object is actually resolved against several available objects and one is returned. I'm thinking of something like a thread pool here, where the use goes, hey, just get me a thread, I need 1, but I don't care which one]


  • The thread pool is a great example of singletons backfiring. The .NET thread pool works like that, and it is a pain. It means I can't create a thread pool for tasks in my application. I have to share it with the .NET class library, any third-party libs I might be using, and god knows what else. I have absolutely no way to tell how likely it is to even have a free thread. A sane design would be to make a thread pool class that anyone can instantiate if they want their own thread pool, and then expose a single global thread pool we can use when we don't care how many other users exist. - jalf
  • @jaif: I feel like you've missed the point of he threadpool. It's there for very quick simple dirty tasks that you want done off the main thread, if you care about getting a free thread or if you want more control you can use the Thread class, or the BackgroundWorker. If you want your own personal user managed pool of threads you can look at implementing a producer-consumer pattern (see half way down this page: albahari.com/threading/part4.aspx). The whole point of the thread pool is that it's meant to balance async work across the whole system, not just your app. - Simon P Stevens
  • Why should I have to implement this pattern myself, when .NET already tried to do it for me? The point is that if they had not hard-coded it as a singleton, it would have done the job across the whole system that it does not, in addition to being useful in smaller scopes within my own app. It is a perfect example of singletons removing flexibility for no reason. I'm not missing the point of the thread pool, I'm saying that with a tiny modification, it would have been far more generally useful. - jalf
  • If you created multiple thread pools how would they balance themselves.I think what you want is something different.I can't see how multiple thread pools would work.The thread pool is a system wide pool of threads,that is there to balance work across apps,and there is just one of them,so a singleton is appropriate way of accessing it.Yes, perhaps MS should implement a producer-consumer thread queue as well,but they can't provide for everything.Anyway, lets not argue too much about it,I'm sure MS have their reasons for doing it the way they did,we have to live with that for good or for bad. - Simon P Stevens

2

I know this is an old thread but no one seemed to mention the actual pattern that fits what the OP was attempting to do. What I believe he is describing a need for is called the Mediator Pattern. SourceMaking is a fantastic site for learning / referencing this kind of information. Definitely my go to place for introducing people to software patterns. Also, it's generally a good idea to not buy into the notion that any design pattern is necessarily inherently good or evil. They all have their use, it's only learning when and where to use them that is the trick. People who state never to use Singletons, to me, don't understand their usefulness.


0

No, they're not necessarily bad.

As for a book, you need to start with the classics.


0

Singletons are not "that bad". If you have a lot of related Singletons and you can replace/consolidate a number of them using a Factory, without losing anything you care about, then that's when you should so do.

As to books, well, there's kind of a canon.


0

0

Google seems to be convinced that Singletons are a bad idea.

That's not to suggest that everything Google does is perfect or that their every opinion is the end of any argument, but they've gone so far as to write this Singleton detector to root them out. Make up your own mind.

Linked


Related

Latest