Design Patterns are one of the most important aspects of software design and architecture. In this blog post, we are going to discuss the “Singleton Design Pattern” and see how to implement the same in the C# programming language. The Singleton Design Pattern is one of the simplest patterns from the Creational category. If you are new to design patterns, I would highly recommend you to read the “Introduction to Design Patterns” article.
What is Singleton Design Pattern
A singleton design pattern helps you to ensure that a class has one and only one instance available throughout the application runtime and provides a global way to access them.
UML Representation
Singleton use-cases
Few of the common use cases for the singleton design pattern are as follows:
- Application Log: A single instance of the logger can be created and used across the application to write log information into the same file.
- Data Sharing: Application configuration, common constants and other values that do not change frequently can be shared as single-point access throughout the application.
- Proxies: Creating service proxies can be an expensive and time-consuming operation, therefore having a service proxy as a singleton can reduce the overhead.
- Design Patterns: Factories, Builders design patterns are some examples that can use singleton internally to instantiate an object.
- Database Connections: Database connection is another area where singleton can be used. The database connection can be shared as single-point access and can also help reduces the overhead of creating connections again and again.
Advantages of Singleton
- Singleton provides single-point access to its instance making it easy to maintain.
- Singleton class can inherit from an interface.
- It can be lazy-loaded.
- Singleton class has static initialization.
- The pattern can be extended to the Factory pattern and help us to hide the dependencies.
Disadvantages of Singleton
- Singleton provides a single access point introducing a global state which makes the unit testing to be difficult. The problem here is that the object using singleton cannot be isolated, hence the object and the singleton is also tested as well.
- The pattern reduces parallelism in the multithreaded environment due to the synchronization lock it uses to ensure single instance creation.
Singleton Implementation in C#
The singleton pattern can be implemented in a number of ways, here we are going to see two simple implementations just to clear the concept, further enhancements and other variants can be searched upon.
Basic Implementation
The first is the most basic way to demonstrate the pattern implementation. In the below code, please note the initialization of the instance variable, this can be done in a number of ways. The below-given code can fail in a multithreaded environment.
namespace DesignPatterns.Patterns { public class Singleton { // Declaring the instance private static Singleton instance; // The constructor is private private Singleton() { } // Initializing the instance on the first call, // this is not the recommended way, the code will // fail in multi-threading environment // The Global Access Point to the instance public static Singleton Instance() { if (instance == null) { instance = new Singleton(); } return instance; } } class Program { static void Main(string[] args) { Singleton firstInstance = Singleton.Instance(); Singleton secondInstance = Singleton.Instance(); if (firstInstance == secondInstance) Console.WriteLine("Great, We are same instances"); else Console.WriteLine("Singleton failed me"); } } }
Code output
Great, We are same instances
Thread-Safe Implementation
If multiple threads are competing to get the singleton instance almost at the same time then it possible that multiple instances can get created as the above code does not take care of the thread synchronization issue. The below code handles the thread synchronization with the locking mechanism and this implementation will be a better choice than the above one.
namespace DesignPatterns.Patterns { public class Singleton { // This is the singleton instance declaration private static Singleton instance; // Declaring and initializing the an object instance this will be used // to synchronize the thread private static readonly object syncObject = new object(); // The constructor's access modifier is set to private private Singleton() { } // Sending a Creator name just for verification purpose public static Singleton Instance(string creatorName) { // If the instance is null, then it needs to be initialized if (instance == null) { // Applying lock (critical section) so that the instance initialization is // completed by one one thread. lock (syncObject) { // Additional check if another thread enter the code after the // first one complete the initialization, it will simply check for // nullness and return. if (instance == null) { instance = new Singleton(); instance.CreatorName = creatorName; } } } return instance; } public string CreatorName { get; set; } } class Program { static void Main(string[] args) { var firstThread = new Thread(() => GetSingleton("First Thread")); var secondThread = new Thread(() => GetSingleton("Second Thread")); firstThread.Start(); secondThread.Start(); firstThread.Join(); secondThread.Join(); } static void GetSingleton(string creatorName) { Singleton singleton = Singleton.Instance(creatorName); Console.WriteLine($"Singleton thread created by# {singleton.CreatorName}"); } } }
Code output
Singleton thread created by# First Thread Singleton thread created by# First Thread
If you want to look further implementations of singleton using C#, I would recommend you look into Jon Skeet’s blog post, the post provides further in-depth knowledge about singleton.
I hope that post gives you an idea about Singleton Design Patterns and you found this post helpful. Thanks for visiting, Cheers!!!
[Further Readings: Introduction to Design Patterns | Microsoft C# Version History | Microsoft .NET Core Versions History | Microsoft .NET Framework Version History | Introduction to WPF in .NET Core | Useful Visual Studio 2019 extensions for database projects | Machine Learning Model Generation | Important Global Visual Studio 2019 Shortcuts | Datasets for Machine Learning | Top 7 Must-Have Visual Studio 2019 Extensions | AI vs ML vs DL – The basic differences | ASP.NET Core Blazor Server Application Project Structure | ASP.NET Core – Blazor Application an Introduction | Top 5 Machine Learning Frameworks to learn in 2020 | Visual Studio 2019 Output Window ]