Are Singletons really that bad?

Design PatternsSingleton

Design Patterns Problem Overview


> 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?

Design Patterns Solutions


Solution 1 - Design Patterns

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.

Solution 2 - Design Patterns

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

Solution 3 - Design Patterns

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.

Solution 4 - Design Patterns

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.

Solution 5 - Design Patterns

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.

Solution 6 - Design Patterns

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.

Solution 7 - Design Patterns

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]

Solution 8 - Design Patterns

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.

Solution 9 - Design Patterns

No, they're not necessarily bad.

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

Solution 10 - Design Patterns

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.

Solution 11 - Design Patterns

Solution 12 - Design Patterns

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionjosef.van.niekerkView Question on Stackoverflow
Solution 1 - Design PatternsjalfView Answer on Stackoverflow
Solution 2 - Design PatternsmandaleekaView Answer on Stackoverflow
Solution 3 - Design PatternskgriffsView Answer on Stackoverflow
Solution 4 - Design PatternsCade RouxView Answer on Stackoverflow
Solution 5 - Design PatternsAndy BView Answer on Stackoverflow
Solution 6 - Design PatternsewernliView Answer on Stackoverflow
Solution 7 - Design PatternsSimon P StevensView Answer on Stackoverflow
Solution 8 - Design PatternsjpefferView Answer on Stackoverflow
Solution 9 - Design PatternsStuView Answer on Stackoverflow
Solution 10 - Design PatternschaosView Answer on Stackoverflow
Solution 11 - Design PatternsJeff Meatball YangView Answer on Stackoverflow
Solution 12 - Design PatternsduffymoView Answer on Stackoverflow