Use the Singleton design pattern to create classes of which only one instance can exist Design patterns are solutions to recurring problems and complexities in software design and are classified into three distinct categories: creational, structural, and behavioral. While creational patterns are used to create and manage the mechanism of creating instances of classes, structural patterns are those that are used to define the structure of types and their relationships — these help to realize the relationships among the entities. Behavioral design patterns are those that deal with object collaboration and delegation of responsibilities among them. The Singleton Design pattern is a creational design pattern that states that one and only one instance of a class can exist throughout the lifetime of an application. In this article, I will present an overview of the Singleton design pattern and show how we can implement it using the C# programming language. Should I use a static class or a Singleton class? A static class is one that can only have static members. You cannot inherit or instantiate a static class. Unlike static classes, Singleton classes can be inherited, can have base class, can be serialized and can implement interfaces. You can implement Dispose method in your Singleton class. So, static classes are much less flexible compared to Singleton classes. The choice between a Singleton class and a static class entirely depends on whether or not you need an instance for your class and the advantages that a Singleton class provides. Static classes can only have static members are these classes cannot be inherited — these classes are sealed implicitly. While static classes are a good choice for storing helper methods, you can use a Singleton class to build a state manager class that can manage state (application state, cache or session, etc.) in your application. Another advantage of a Singleton class is that it can be initialized lazily or asynchronously. You can’t do this with a static class — it is initialized when it is loaded in the memory. Implementing a Singleton class Well, let’s now dig into some code. The following code snippet illustrates a Singleton class. public class StateManager { private static StateManager instance; private StateManager() {} public static StateManager Instance { get { if (instance == null) { instance = new StateManager(); } return instance; } } } Note how the object of the StateManager class has been created. The static property Instance can be used to retrieve a reference to the instance of the StateManager class. The StateManager class is sealed to prevent inheritance and it has a private constructor so that no instance of it can be created. OK, but what about thread safety? The following code listing shows a modified version of the StateManager class that has thread safety implemented. public sealed class StateManager { private static volatile StateManager instance; private static object lockObj = new Object(); private StateManager() {} public static StateManager Instance { get { if (instance == null) { lock (lockObj) { if (instance == null) instance = new StateManager(); } } return instance; } } } The volatile keyword is used to ensure that the object is initialized prior to being accessed. This implementation is thread safe — a check is made to see if an instance of the StateManager class has been created prior to creating the instance. Note that instead of locking on the typeof(StateManager) you should lock on a static object that is private to the StateManager class. This ensures that the potential risks of performance issues and deadlocks are eliminated. The next version of our StateManager class implements lazy initialization using a nested class. public sealed class StateManager { private StateManager() { } public static StateManager Instance { get { return Nested.instance; } } private class Nested { static StateManager() { } internal static readonly StateManager instance = new StateManager(); } } You might not need full laziness in most cases unless your Singleton class needs to do some initialization that would be resource consuming and takes up a lot of time. Having said that I would prefer to use lazy initialization only if there are no resource consuming initialization operations needed in the class. Note that a static constructor is invoked when the class is instantiated or when a static member of the class is accessed.The explicit static constructor is used in the example earlier to inform the runtime not to mark the type (the StateManager class in this example) as beforefieldinit. Our final version of the StateManager class is even better – it leverages the System.Lazy type (available from .Net Framework 4) to make the laziness seamless and simple. public sealed class StateManager { private static readonly Lazy<StateManager> singleton = new Lazy<StateManager>(() => new StateManager()); public static StateManager Instance { get { return singleton.Value; } } private StateManager() { } } You can learn more on Singleton design pattern and how it can be implemented in C# from this MSDN article. Related content feature 14 great preprocessors for developers who love to code Sometimes it seems like the rules of programming are designed to make coding a chore. Here are 14 ways preprocessors can help make software development fun again. By Peter Wayner Nov 18, 2024 10 mins Development Tools Software Development feature Designing the APIs that accidentally power businesses Well-designed APIs, even those often-neglected internal APIs, make developers more productive and businesses more agile. By Jean Yang Nov 18, 2024 6 mins APIs Software Development news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages Resources Videos