Home > OS >  Proper singleton class implementation
Proper singleton class implementation

Time:09-13

I started my design patterns learning with a singleton class. Could you explain me the difference between the following Instance property implementations?

public class Singleton
{
    private static Singleton _instance;
    public static Singleton Instance => _instance ?? (_instance = new Singleton());
}
public class Singleton
{
    public static Singleton Instance => _instance.Value;

    private static readonly Lazy<Singleton> _instance =
        new Lazy<Singleton>(() => new Singleton());
}

CodePudding user response:

public class Singleton
{
    private static Singleton _instance;
    public static Singleton Instance => _instance ?? (_instance = new Singleton());
}

The above implementation of sigleton is not thred safe. As static variables are always shared by all the threads in the process. So two threads can evaluate that _instance is equal to null and two threads will create two instances of Singleton which is not eligible.

The following implementation is thread safe as it uses Lazy<T>:

public class Singleton
{
    public static Singleton Instance => _instance.Value;

    private static readonly Lazy<Singleton> _instance =
        new Lazy<Singleton>(() => new Singleton());
}

As msdn says about Lazy:

You can use one of the simple constructors whose default behavior is to create a thread-safe Lazy object, so that only one instance of the lazily instantiated object is created no matter how many threads try to access it.

CodePudding user response:

Singleton pattern has evolved quite a bit since is first presentation in the GoF book. The classical implementation of the pattern requires a static way to access the instance, example given:

 public class Singleton
 {
     public static Singleton Instance => ....

     public virtual void CallMe() { ... }
 }

However this approach has a big drawback when it's time to write tests. A "Client" class would reference the singleton in the following way:

public class Client
{
    public void DoSomething()
    {
         Singleton.Instance.CallMe();
    }
}

With this shape it is impossible to mock the implementation of the CallMe method and write a unit test for the DoSomething method.

What should be done to realize a singleton instance of a class is to leave it up to the IoC container, in this way:

 public class Singleton
 {
    //no static properties
    public virtual void CallMe() { ... }
  }

  public class Client
  {
     private readonly Singleton _singleton;
     public Client(Singleton singleton)
     {
        _singleton = singleton;
     }
     public void DoSomething() => _singleton.CallMe();
  }

  //where you declare your services
  builder.Services.AddSingleton<Singleton>();
  builder.Services.AddScoped<Client>();
  • Related