72

There is a widely accepted opinion that Singleton is an anti-pattern. As usual, there are always exceptions to the rule. Can you explain why Singleton is a bad choice in general and give an example of some valid use cases for it?

2

5 Answers 5

34

The two main criticisms of Singletons fall into two camps from what I've observed:

  1. Singletons are misused and abused by less capable programmers and so everything becomes a singleton and you see code littered with Class::get_instance() references. Generally speaking there are only one or two resources (like a database connection for example) that qualify for use of the Singleton pattern.
  2. Singletons are essentially static classes, relying on one or more static methods and properties. All things static present real, tangible problems when you try to do Unit Testing because they represent dead ends in your code that cannot be mocked or stubbed. As a result, when you test a class that relies on a Singleton (or any other static method or class) you are not only testing that class but also the static method or class.

As a result of both of these, a common approach is to use create a broad container object to hold a single instance of these classes and only the container object modifies these types of classes while many other classes can be granted access to them to use from the container object.

4
  • 6
    I just would like to say that you can mock static methods in Java with JMockit(code.google.com/p/jmockit). It's a very handy tool.
    – Michael K
    Commented Nov 3, 2010 at 14:19
  • 3
    Some thoughts: the container is a Singleton, so you haven't gotten rid of Singletons. Also, if you're writing a library with a public API, you can't force the user of your API to use your container. If you need a global resource manager in your library (protecting access to a single physical resource, for instance) then you need to use a Singleton. Commented Nov 30, 2010 at 16:20
  • 3
    @Scott Whitlock why does it need to be a singleton? Just because there's only a single instance doesn't make it so. Any IoC library will manage this kind of dependency...
    – MattDavey
    Commented Sep 13, 2011 at 8:35
  • This solution proposed it also known as Toolbox
    – cregox
    Commented Nov 13, 2013 at 15:06
48

I agree that it is an anti-pattern. Why? Because it allows your code to lie about its dependencies, and you can't trust other programmers to not introduce mutable state in your previously immutable singletons.

A class might have a constructor that only takes a string, so you think it is instantiated in isolation and does not have side effects. However, silently, it is communicating with some sort of public, globabally available singleton object, so that whenever you instantiate the class, it contains different data. This is a big problem, not only for users of your API, but also for the testability of the code. To properly unit-test the code, you need to micro-manage and be aware of the global state in the singleton, to get consistent test results.

1
  • 1
    Wish I could upvote more than once!
    – MattDavey
    Commented Sep 13, 2011 at 8:37
37

The Singleton pattern is basically just a lazily initialized global variable. Global variables are generally and rightly considered evil because they allow spooky action at a distance between seemingly unrelated parts of a program. However, IMHO there is nothing wrong with global variables that are set once, from one place, as part of a program's initialization routine (for example, by reading a config file or command line arguments) and treated as constants thereafter. Such use of global variables is different only in letter, not in spirit, from having a named constant declared at compile time.

Similarly, my opinion of Singletons is that they're bad if and only if they are used to pass mutable state between seemingly unrelated parts of a program. If they don't contain mutable state, or if the mutable state that they do contain is completely encapsulated so that users of the object don't have to know about it even in a multithreaded environment, then there's nothing wrong with them.

4
  • 3
    So in other words you are against any use of a database in a program. Commented Jul 31, 2011 at 5:53
  • There is a famous google tech talk video that echos your opinion youtube.com/watch?v=-FRm3VPhseI Commented Mar 17, 2013 at 2:01
  • 2
    @KendallHelmstetterGelner: There is a difference between state and secondary storage. It is unlikely you can hold a whole DB in memory. Commented Mar 17, 2013 at 2:04
  • 1
    @KendallHelmstetterGelner how so? You can still use a database that isn't named in global scope, so long as it is passed to you.
    – Caleth
    Commented Aug 11, 2020 at 8:30
8

Why do people use it?

I have seen quite a number of singletons in the PHP world. I don't remember any use case where I found the pattern to be justified. But I think I got an idea about the motivation why people did use it.

  1. Single instance.

    "Use a single instance of class C throughout the application."

    This is a reasonable requirement e.g. for the "default database connection". It does not mean you won't ever create a second db connection, it just means you usually work with the default one.

  2. Single instantiation.

    "Do not allow class C to be instantiated more than once (per process, per request, etc)."

    This is only relevant if instantiating the class would have side effects that conflict with other instances.

    Often these conflicts can be avoided by redesigning the component - e.g. by eliminating side effects from the class constructor. Or they can be solved in other ways. But there might still be some legit use cases.

    You should also think about whether the "only one" requirement really means "one per process". E.g. for resource concurrency, the requirement is rather "one per entire system, across processes" and not "one per process". And for other things it is rather per "application context", and you just happen to have one application context per process.

    Otherwise, there is no need to enforce this assumption. Enforcing this also means you cannot create a separate instance for unit tests.

  3. Global access.

    This is legit only if you have no proper infrastructure to pass objects around to the place where they are used. This could mean that your framework or environment sucks, but it might not be within your powers to fix that.

    The price is tight coupling, hidden dependencies, and everything that's bad about global state. But you are probably already suffering these.

  4. Lazy instantiation.

    This is not a necessary part of a singleton, but it seems the most popular way to implement them. But, while lazy instantiation is a nice thing to have, you don't really need a singleton to achieve that.

Typical implementation

The typical implementation is a class with a private constructor, and a static instance variable, and a static getInstance() method with lazy instantiation.

In addition to the problems mentioned above, this bites with the single responsibility principle, because the class does control its own instantiation and life cycle, in addition to the other responsibilities that the class already has.

Conclusion

In many cases, you can achieve the same result without a singleton, and without global state. Instead, you should use dependency injection, and you might want to consider a dependency injection container.

However, there are use cases where you have the following valid requirements remaining:

  • Single instance (but not single instantiation)
  • Global access (because you are working with a bronze age framework)
  • Lazy instantiation (because it is just nice to have)

So, here is what you can do in this case:

  • Create a class C that you want to instantiate, with a public constructor.

  • Create a separate class S with a static instance variable and a static S::getInstance() method with lazy instantiation, that will use class C for the instance.

  • Eliminate all side effects from the constructor of C. Instead, put these side effects in the S::getInstance() method.

  • If you have more than one class with the above requirements, you may consider to manage the class instances with a small local service container, and use the static instance only for the container. So, S::getContainer() will give you a lazy-instantiated service container, and you get the other objects from the container.

  • Avoid calling the static getInstance() where you can. Use dependency injection instead, whenever possible. Especially, if you use the container approach with multiple objects that depend on each other, then none of these should have to call S::getContainer().

  • Optionally create an interface that class C implements, and use this to document the return value of S::getInstance().

(Do we still call this a singleton? I leave this to the comment section..)

Benefits:

  • You can create a separate instance of C for unit testing, without touching any global state.

  • Instance management is separated from the class itself -> separation of concerns, single responsibility principle.

  • It would be quite easy to let S::getInstance() use a different class for the instance, or even dynamically determine which class to use.

1

Personally I will use singletons when I need 1, 2, or 3, or some limited amount of the objects for the particular class in question. Or I want to convey to the user of my class that I do not want multiple instances of my class being created for it to function properly.

Also I will only use it when I need to use it almost everywhere in my code and I don't want to pass an object as a parameter to each class or function that needs it.

In addition I will only use a singleton if it does not break another function's referential transparency. Meaning given some input it will always produce the same output. I.e. I don't use it for global state. Unless possibly that global state is initialized once and never changed.

As for when not to use it, see the above 3 and change them to the opposite.

2
  • 3
    -0 but i nearly -1. I would rather pass it everywhere in my code instead of use a singleton BUT if i am really lazy i may do that. I'd use global vars instead if i am able to or static members. global vars are really much preferable (to me) then singletons. Globals dont lie
    – user2528
    Commented Dec 6, 2010 at 13:15
  • Global variables have their destructors called when the application exits, in unpredictable order. That means it is possible to try to access the singleton after it has been destructed.
    – gnasher729
    Commented Jan 20, 2023 at 0:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.