Categories: Design Pattern

Creational Patterns – Singleton

Singleton – A class of which only a single instance can exist.

From Design Pattern – Creational Patterns

Structure

Singleton pattern Class diagram UML

Applicability

Using the Singleton pattern is when all clients available to call its class and only a single instance available in the program. For example, a single object share with other parts of the program to use.

Using the Singleton pattern is when the program or the project needs stricter to controller the global variable.

Some real-time scenarios about the Singleton pattern that shows below:

  • Service Proxies – It is a service API that is an extensive operation in an application. This process can take most of the time to create a client service for invoking the service API, which can improve the application performance.
  • Facades – Create the database connection as Singleton, which can improve the application performance.
  • Logs – The file’s I/O operation performance is an expensive operation. Create the logger as a Singleton pattern, which can improve the I/O operation performance.
  • Data sharing – Global variable share to other parts of the program to use, such as the constant values and configuration values.
  • Caching – We can get data from the database, which is a time-consuming process, so you can cache the master and configuration in the memory, which avoids the database calls. Use the singleton pattern to handle the cache with thread synchronization, which can improve the application performance.

Pros and Cons

PRONS

  • Ensure a class has only a single instance and provide global point access to it.
  • Singleton object is initialized only by its request for the first time.

CONS

  • Violates the Single-Responsibility Principle, which means it solves two problems at the same time.
  • Can mask lousy design, for instance, which means the components cleanly know to each other.
  • It may be difficult to test the singleton client code because most test frameworks rely on inheritance mechanisms when making the mock objects. Most singleton pattern’s class is private, so overriding static methods is impossible in most computer languages, which means the developer needs to create a way to mock the singleton or don’t write the tests, or don’t use the singleton pattern.

How to Implement

#1 Basic Sample

The singleton patterns have six basic samples which show below:

  1. Non-thread-safe (Naïve Singleton)
  2. Simple thread safety via locking
  3. Double-checked locking
  4. Safety through initialization
  5. Safe and fully lazy static initialization
  6. Using .NET 4.X’s Lazy<T> type
  1. Non-thread-safe (Naïve Singleton)
public sealed class Singleton
{
 public static Guid guid { get; set; }

 private Singleton() { }

 private static Singleton instance;

 public static Singleton GetInstance()
 {
  if (instance == null)
  {
   guid = Guid.NewGuid();

   instance = new Singleton();
  }
  return instance;
 }

 public static Guid someBusinessLogic() => guid;
}
  
class Program
{
 static void Main(string[] args)
{
 // The client code.
 var s1 = Singleton.GetInstance();
 var s2 = Singleton.GetInstance();

 if (s1 == s2)
 {
  Console.WriteLine("Singleton work, variables contain same instances.");
  Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
  Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
 }
 else
  Console.WriteLine("Singleton failed, variables contain different instances.");

 Console.ReadKey();
 }
}

The above sample source code is not thread-safe. Two various tasks can pass the if-statement condition, which creates instances that violate the singleton pattern concepts. Maybe the instances have been made before the c sharp compiler mechanism evaluates the expression. However, the computer’s memory doesn’t ensure other threads will see the new instance memory values unless the other thread’s source code has passed suitable memory barriers.

2. Simple thread safety via locking

public sealed class Singleton
{
 public static Guid guid { get; set; }

 private Singleton() { }

 private static Singleton instance;
 private static readonly object padlock = new object();

 public static Singleton GetInstance()
 {
  lock (padlock)
  {
   if (instance == null)
   {
    guid = Guid.NewGuid();

    instance = new Singleton();
   }
   return instance;
  }
 }

 public static Guid someBusinessLogic() => guid;
}

class Program
{
 static void Main(string[] args)
 {
  // The client code.
  var s1 = Singleton.GetInstance();
  var s2 = Singleton.GetInstance();

  if (s1 == s2)
  {
   Console.WriteLine("Singleton work, variables contain same instances.");
   Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
   Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
  }
  else
   Console.WriteLine("Singleton failed, variables contain different instances.");

  Console.ReadKey();
 }
}

The second sample implements the thread-safe concepts. The thread can lock on share objects and check whether the instance has been created by other source code before creating the instance. This sample can solve the memory barrier issues and ensures the only one task will create an instance. Unfortunately, this sample will affect the performance suffers because a lock condition is acquired every time the instances are requested.

3. Double-checked locking

public sealed class Singleton
{
 public static Guid guid { get; set; }

        private Singleton() { }

        private static Singleton instance;
        private static readonly object padlock = new object();

        public static Singleton GetInstance()
        {
  if (instance == null)
  {
   lock (padlock)
   {
                      if (instance == null)
                      {
     guid = Guid.NewGuid();

     instance = new Singleton();
                      }                    
                 }
             }
             return instance;
        }

        public static Guid someBusinessLogic() => guid;
}

class Program
{
 static void Main(string[] args)
 {
  // The client code.
  var s1 = Singleton.GetInstance();
  var s2 = Singleton.GetInstance();

  if (s1 == s2)
  {
   Console.WriteLine("Singleton work, variables contain same instances.");
   Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
   Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
  }
  else
   Console.WriteLine("Singleton failed, variables contain different instances.");

  Console.ReadKey();
 }
}

The third sample has the double-check mechanism, but the performance issue still exists without solving it. Unfortunately, this sample has four downsides to the singleton pattern shows below:

  • It doesn’t work in Java. This may seem an odd thing to comment on, but it’s worth knowing if you ever need the singleton pattern in Java, and C# programmers may well also be Java programmers. The Java memory model doesn’t ensure that the constructor completes before the reference to the new object is assigned to instance. The Java memory model underwent a reworking for version 1.5, but double-check locking is still broken after this without a volatile variable (as in C#).
  • Without any memory barriers, it’s broken in the ECMA CLI specification too. It’s possible that under the .NET 2.0 memory model (which is stronger than the ECMA spec) it’s safe, but I’d rather not rely on those stronger semantics, especially if there’s any doubt as to the safety. Making the instance variable volatile can make it work, as would explicit memory barrier calls, although in the latter case even experts can’t agree exactly which barriers are required. I tend to try to avoid situations where experts don’t agree what’s right and what’s wrong!
  • It’s easy to get wrong. The pattern needs to be pretty much exactly as above – any significant changes are likely to impact either performance or correctness.
  • It still doesn’t perform as well as the later implementations.

From C# in depth – Implementing the Singleton Pattern in C#

4. Safety throught initialization

public sealed class Singleton
{
 public static Guid guid { get; set; }

 static Singleton() { }
  private Singleton() { }
 private static readonly Singleton instance = new Singleton();

 public static Singleton GetInstance()
 {
  guid = Guid.NewGuid();
  return instance;
 }

 public static Guid someBusinessLogic() => guid;
}

class Program
{
 static void Main(string[] args)
 {
  // The client code.
  var s1 = Singleton.GetInstance();
  var s2 = Singleton.GetInstance();

  if (s1 == s2)
  {
   Console.WriteLine("Singleton work, variables contain same instances.");
   Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
   Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
  }
  else
   Console.WriteLine("Singleton failed, variables contain different instances.");

  Console.ReadKey();
 }
}

Static constructor characteristics in c# are appointed to execute. Only when the class instance creates or the static members are referenced and run only once per AppDomain. Whatever else situation, it must be running faster than other adding source code for checking a new instance in previous samples. This solution will make a couple of wrinkles that show below:

  • It’s not as lazy as the other implementations. In particular, if you have static members other than Instance, the first reference to those members will involve creating the instance. This is corrected in the next implementation.
  • There are complications if one static constructor invokes another which invokes the first again. Look in the .NET specifications for more details about the exact nature of type initializers – they’re unlikely to bite you, but it’s worth being aware of the consequences of static constructors which refer to each other in a cycle.
  • The laziness of type initializers is only guaranteed by .NET when the type isn’t marked with a special flag called beforefieldinit. Unfortunately, the C# compiler (as provided in the .NET 1.1 runtime, at least) marks all types which don’t have a static constructor (i.e. a block which looks like a constructor but is marked static) as beforefieldinit. It will affects performance.

From C# in depth – Implementing the Singleton Pattern in C#

This sample is a shortcut method for creating instances that are a public static read-only variable and getting rid of the property entirely, which lets the basic skeleton code is tiny.

5. Safe and fully lazy static initialization

public sealed class Singleton
{
 public static Guid guid { get; set; }

 private Singleton() { }

 public static Singleton GetInstance {
 get {
  guid = Guid.NewGuid();
  return Nested.instance;
  }
 }

 private class Nested
 {
  static Nested()
  { }

  internal static readonly Singleton instance = new Singleton();
 }

 public static Guid someBusinessLogic() => guid;
}


class Program
{
 static void Main(string[] args)
 {
  // The client code.
  var s1 = Singleton.GetInstance;
  var s2 = Singleton.GetInstance;

  if (s1 == s2)
  {
   Console.WriteLine("Singleton work, variables contain same instances.");
   Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
   Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
  }
  else
   Console.WriteLine("Singleton failed, variables contain different instances.");

  Console.ReadKey();
 }
}

This sample instance uses the embedding method for the static members, which only happens the first time calling. It means it is fully lazy, but all the performance benefits of the previous ones still exist. The embedding method can be called the enclosing class’s private member. However, it isn’t true; therefore, the need for an instance to be internal here. It doesn’t bring any other problems as the class itself is private, but it can let the source code become complex.

6. Using .NET 4.X’s Lazy<T> type

public sealed class Singleton
{
 public static Guid guid { get; set; }

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

 public static Singleton GetInstance
 {
  get {
   guid = Guid.NewGuid();
   return lazy.Value;
   }
 }

 public static Guid someBusinessLogic() => guid;
}

class Program
{
 static void Main(string[] args)
 {
  // The client code.
  var s1 = Singleton.GetInstance;
  var s2 = Singleton.GetInstance;

  if (s1 == s2)
  {
   Console.WriteLine("Singleton work, variables contain same instances.");
   Console.WriteLine("Singleton 1 Guid: {0}", Singleton.guid.ToString());
   Console.WriteLine("Singleton 2 Guid: {0}", Singleton.guid.ToString());
  }
  else
   Console.WriteLine("Singleton failed, variables contain different instances.");

  Console.ReadKey();
 }
}

The #6 sample is base on the project’s NET 4 or higher, then using the System.Lazy type, which can make let developers easy to use it. The developers only do a thing that uses a delegate to the constructor, which calls the Singleton constructor, which is done with a lambda expression and implicitly uses LazyThreadSafetyMode.ExecutionAndPublication as the thread-safety mode for the Lazy.

#2 Web Application Project

Step 1 Create an interface class whose name sets “IOperation” under the Core project. Create another class file which name sets “Operation” under the Infra project.

Fig 1 Solution explorer – Core project & Infra project

Step 2 The “Operation” class file inherits the IOperation interface class file under the Infra project. The “IOperationSingleton” interface class adds a GET guid string method and inherits the IOperation interface class; then, the “Operation” class file inherits it.

The IOperation file source code shows below:

public interface IOperation
{
 string OperationId { get; }
}

public interface IOperationTransient : IOperation
{
 new string OperationId();
}
public interface IOperationScoped : IOperation
{
 new string OperationId();
}
public interface IOperationSingleton : IOperation
{
 new string OperationId();
}
Fig 2 Operation class file source code

Step 3 Add the Controller file and the View file under the web project, then calling the IOperation class’s way from the Controller file to layout the View file. The Controller file name sets “SingletonController.” The View file part only creates the “Index” page under the web project’s Views folder.

Fig 3 Singleton controller file source code

Step 4 Add the Singleton in the startup.cs file, which is under the web project.

services.AddSingleton<IOperationSingleton, Operation>();

Reference

davidsky69

View Comments

Recent Posts

API Gateway in .NET 5 with Ocelot

What is the API gateway? An API gateway is an API management tool that sits…

4 years ago

.NET 5 application with Onion architecture

The .NET 5 SDK is a kind of milestone in the .NET world. The .NET…

4 years ago

SOLID Principles – Dependency inversion principle

In object-oriented design, the dependency inversion principle is a specific methodology for loosely coupling software…

4 years ago

SOLID Principles – Interface segregation principle

In the field of software engineering, the interface segregation principle (ISP) states that no code…

4 years ago

SOLID Principles – Liskov substitution principle

Subtype Requirement: Let  be a property provable about objects  of type T. Then  should be true for objects  of type S where S is…

4 years ago

SOLID Principles – Open-closed principle

In object-oriented programming, the open–closed principle states "software entities (classes, modules, functions, etc.) should be…

4 years ago