Skip to main content

Singleton

complexitypopularity

Guarantee a class has exactly one instance and give the whole program a single access point to it.

The problem

Singleton solves two problems at once, which is already a confession that it violates the Single Responsibility Principle.

One instance. Sometimes a class must have exactly one live object, usually because it guards a shared resource such as a database or a file. Ask for a second one and you should receive the first. A regular constructor cannot do that: constructors are contractually required to return something new.

One access point. The alternative is a global variable, and globals are wonderful right up until any code anywhere overwrites the contents and takes the app down with it.

Singleton gives you global reach while protecting the instance from being replaced, and it keeps the enforcement in one class instead of scattered across the codebase.

The solution

Every implementation does the same two things.

Make the default constructor private, so no other code can use new on the class. Then add a static creation method that acts as a constructor: it calls the private constructor, caches the object in a static field, and returns that same object on every later call. If your code can see the class, it can call the method, and it always gets the same object back.

The instance is created on the first call rather than at startup, which is called lazy initialization. That is a genuine benefit for expensive resources, and it is also where the threading bug lives - see the pitfalls.

ReportServiceAuditServiceDatabase (class)The one instanceDatabase.getInstance()1if (instance == null)2lock, then re-check null3new Database()4Database.getInstance()5returns cached instance6
  1. 1The first caller anywhere in the program asks for the instance. Note that it did not receive one; it went and fetched it.
  2. 2The static field is empty, so this call is the one that pays for construction. That is lazy initialization.
  3. 3Under threads, a second caller may already be mid-construction. Take the lock and test again before committing.
  4. 4The private constructor runs exactly once and the result is stashed in the static field.
  5. 5A completely unrelated class calls the same static method later.
  6. 6The field is populated, so it short-circuits. Both services now hold the same object and neither of them was told about the other.

Structure

The structure diagram is famously small: one class with a private constructor, a private static field, and a public static getInstance(). The interesting box is the fourth one here, the dependency-injected alternative that buys the same guarantee without the global.

«interface»ConnectionProviderget(): DatabaseTHEDatabase- static instance: Database- Database()+ static getInstance(): Database+ query(sql)THEReportServicerun()CLIENTAuditServicerecord(event)ANOTHER
uses

Code

Same example three ways: a database connection that exists exactly once.

// The tempting version: a global variable.
global dbConnection = new Database("prod-host")
 
// Every module reaches for it directly.
class ReportService is
method run() is
dbConnection.query("SELECT ...")
 
// And nothing whatsoever stops this:
dbConnection = null // somewhere in a test
dbConnection = new Database("localhost") // someone else, on a whim
// Handy, and precisely one typo away from taking down the app.
// One instance, guaranteed, with a global access point:
class Database is
private static field instance: Database
private constructor Database() is
// ...
 
public static method getInstance(): Database is
if (this.instance == null) then
acquireThreadLock() and then
if (this.instance == null) then
this.instance = new Database()
return this.instance
 
// Nothing outside the class can replace or duplicate the instance:
db = Database.getInstance()
// db2 = new Database() // will not compile, the constructor is private
 
// The honest alternative, when testability matters more than convenience:
// create exactly one Database in your composition root and pass it in.
class ReportService is
constructor ReportService(db: Database) is
this.db = db
// Same single instance, no global reach, trivially faked in tests.
// The Database class controls its own instance count and hands the
// same connection to everyone who asks.
class Database is
// The cache must be static: it belongs to the class, not an object.
private static field instance: Database
 
// A private constructor slams the door on the new operator.
private constructor Database() is
// Expensive setup: open the socket, authenticate, warm the pool.
 
// The only way in. First call builds, all later calls return.
public static method getInstance(): Database is
if (this.instance == null) then
acquireThreadLock() and then
// Another thread may have finished while this one
// waited for the lock, so ask the question again.
if (this.instance == null) then
this.instance = new Database()
return this.instance
 
// A singleton is still an object, so give it real work to do.
public method query(sql) is
// Every query in the app goes through here, which makes this
// a convenient place for throttling, caching or logging.
 
class Application is
method main() is
Database foo = Database.getInstance()
foo.query("SELECT ...")
 
Database bar = Database.getInstance()
bar.query("SELECT ...")
// foo and bar are the same object. Neither caller was told so.

When to use it

  • A class genuinely must have one instance shared by the whole program, most classically a connection or a configuration object guarding a shared resource.
  • You want stricter control over something that would otherwise be a global variable. Singleton at least guarantees nothing outside the class can swap the instance out.
  • Even then, ask first whether one instance created in your composition root and passed to the objects that need it would do the same job. Usually it would, and it tests better.

Pitfalls

This is the pattern that comes with a health warning. It is popular, it is easy, and it is widely considered a semi-antipattern for reasons that all hold up.

  • It is global state wearing a nicer hat. Any code can reach it, so dependencies stop appearing in constructors and signatures. Your call graph becomes an invisible web that nothing in the type system documents.
  • It fights your tests. The instance survives from one test to the next, carrying state with it. Mocking frameworks mostly rely on inheritance, and static methods cannot be overridden in most languages, so faking it takes contortions or a back door.
  • It masks bad design. Reaching for a singleton is often the symptom of components that know far too much about each other. The pattern hides the coupling rather than removing it.
  • Threads. Naive lazy initialization lets two threads construct two instances. You need double-checked locking with a volatile field, an eagerly initialized static, an enum in Java, or a module-level object in Python.
  • It violates SRP openly. Instance control and global access are two responsibilities bolted together, and the pattern makes no apology for it.

Don't confuse it with

  • A static utility class. If you never need the instance to implement an interface, hold state, or be substituted, static methods are simpler and more honest. Singleton is only worth the machinery when the object-ness matters.
  • Flyweight. Flyweights look like shared instances too, but a flyweight class can have many instances with different intrinsic state, and they are immutable. A singleton is one object and may cheerfully mutate.
  • Dependency-injected single instances. A container that creates one instance and injects it everywhere gives you the same uniqueness with none of the global access. This is what most people should reach for, and the reason Singleton appears less in new code than its fame suggests.
  • Facade. A facade is often implemented as a singleton because one is usually enough, but the intents are unrelated: facade simplifies a subsystem, singleton counts instances.

Check yourself

Question 1 of 5

Why can a constructor not implement Singleton by itself?