The Singleton Pattern

Photo by Robert F. on Unsplash

 

The Singleton Pattern is probably the most widely used (and abused) design pattern, which is a shame because it has some serious flaws. 

Developers tend to apply the Singleton Pattern when they want to ensure the existence of only one object instance. One object means only a single copy of the state exists at any given point in time.

Some situations where we might want to have only a single instance are for a database connection, logger, or cache. In these use cases, we often desire only a single instance of the same state. Alternatively, some objects could be very resource-intensive to create. An optimisation might be to instantiate such an expensive object only once and then reuse it.

Here is a description of how to create a Singleton:

  1. Declare the constructor as private, to avoid direct instantiation.
  2. Declare a private static Instance property (or class member) to hold our single instance.
  3. Define a public static method (or property) that returns the singleton instance. We can use lazy instantiation to create a new instance when it doesn’t exist yet.

A simple Singleton implementation would look like this:

  public class Singleton
  {
     private static Singleton Instance = null;

     private Singleton()
     { } 

     public static Singleton GetInstance()
     {
        if (Instance == null)
           Instance = new Singleton();
        return Instance;
     }

     // Instance methods/properties to call on our Singleton instance.
     public string Data { get; set }
     // ...
  }

How does this code behave?

  var singleton = Singleton.GetInstance();
  var anotherReference = Singleton.GetInstance();

  singleton.Data = "abc";
  Console.WriteLine($"Set singleton.Data to {singleton.Data}");
  Console.WriteLine($"singleton.Data: {singleton.Data}");
  Console.WriteLine($"anotherReference.Data: {anotherReference.Data}");

  Console.WriteLine();

  anotherReference.Data = "xyz";
  Console.WriteLine($"Set anotherReference.Data to {anotherReference.Data}");
  Console.WriteLine($"singleton.Data: {singleton.Data}");
  Console.WriteLine($"anotherReference.Data: {anotherReference.Data}");

And the output is:

  Set singleton.Data to abc
  singleton.Data: abc
  anotherReference.Data: abc

  Set anotherReference.Data to xyz
  singleton.Data: xyz
  anotherReference.Data: xyz

As we see, irrespective of which reference we are using, we are referring to to the same instance. A change to Data in one is reflected in the other. 

The Singleton pattern has its problems:

  • If we change our minds about the class being a Singleton, we will need to modify all the calls to GetInstance(). Potentially such a change will touch many areas of our application.
  • The GetInstance() method in our simple example is not threadsafe. A careless implementation of GetInstance() could have multiple concurrent threads instantiate several copies of the data. When we have simultaneous threads, GetInstance() will require a locking mechanism.
  • Last but not least, Singleton code can be tricky in unit tests. The Singleton may represent an entity that we would prefer to mock rather than refer to the real object in a unit test, like a database connection. Naturally, we don’t want to call into a database in a unit test. However, the GetInstance() method is static, and statics are notoriously difficult to mock. We may have to use advanced unit testing techniques, like Extract & Override, to overcome this obstacle. We’ll look into Extract & Override another time.

There is a better alternative to the Singleton Pattern. We’ll check this out tomorrow.

 

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply