Singleton Design Pattern In C#

The Singleton design pattern is a type of creational design pattern in C#. Its main objective is to guarantee that a class has a single instance while offering a universal way to access that instance. This technique proves beneficial when managing entry to a shared resource or ensuring that a lone object orchestrates activities within an application.

The Singleton design pattern in C# guarantees that only one instance of a class is created and offers universal access to it. Its time and space complexities are usually constant (O(1)), which makes it effective for overseeing shared resources like configuration information or database connections. This pattern enforces thread-safe creation when implemented with double-check locking.

However, it simplifies access to a single instance, and developers should use it cautiously to prevent the introduction of global state and uphold a clear separation of concerns within their codebases. The Singleton pattern continues to be a useful asset for addressing particular design challenges that necessitate centralized control and coordination.

Common Us? Cas?s for th? Singl?ton Patt?rn:

Database Connection Pool: When working with databases, a Singleton pattern can be employed to oversee a connection pool, guaranteeing efficient utilization of connections.

Logging: A Singleton Logger class ensures that all log messages are directed to a single log file or destination.

Configuration Management: When you possess configuration parameters that require uniformity throughout the application, a Singleton can store and grant access to these settings.

Managing a cache of frequently accessed data can gain advantages from employing a Singleton pattern to uphold a single cache instance.

Structure of Singleton Design Pattern:

There are numerous essential aspects in the configuration of the Singleton Pattern in C#. The primary elements of the Singleton Design Pattern include:

The class contains a private constructor to prevent direct instantiation from external code.

Instance Variable: This variable holds the sole instance of the class and is commonly designated as static to guarantee shared access.

A public static method is available for accessing the single instance through Static Method for Instance Access. This method guarantees the creation of the instance if it is not present or returns the existing instance.

Characteristics of Singleton Design Pattern:

The Singleton design pattern possesses numerous essential features that delineate its functionality and intent. Grasping these traits is crucial for efficiently incorporating and leveraging the Singleton pattern in your software architecture.

Singl? Instanc?: The primary feature of the Singl?ton design pattern is its guarantee of a sole instance of the class existing throughout the application's lifespan. This ensures that each request for the Singl?ton instance consistently returns the identical, singular instance.

Global Access: The Singleton offers a universal means of accessing its lone instance. This implies that any section of the code can reach the Singleton instance without the requirement to pass references to it. This broad access streamlines the interaction process with the Singleton object.

A private constructor in a Singleton class is commonly implemented to enforce the single instance rule. This practice restricts external code from generating extra instances of the class through the new keyword. The private constructor stands out as a key feature that differentiates a Singleton from a standard class.

Lazy Initialization: In numerous scenarios, the Singleton instance is generated solely upon the initial request. This process is referred to as lazy initialization. Lazy initialization has the potential to enhance performance because the Singleton object is not instantiated until it is specifically required. This approach aids in resource conservation when the Singleton remains inactive throughout the lifespan of the application.

Static Instance Variable: The Singleton class usually includes a private static variable that stores the single instance. This variable ensures that the instance is shared among all code that accesses it. It is commonly referred to as "instance" or a similar name.

Program:

Let's consider an illustration to showcase the Singleton Design Pattern in C#:

Example

using Syst?m;

public s?al?d class Singl?ton
{
    // St?p 1: Privat? static instanc? variabl? with lazy initialization
    privat? static volatil? Singl?ton instanc?;
    privat? static obj?ct syncRoot = n?w Obj?ct(); // For locking

    // Oth?r instanc? variabl?s (if n??d?d)
    privat? string som?Data;

    // St?p 2: Privat? constructor
    privat? Singl?ton()
    {
        // Initialization cod? h?r? (if n??d?d).
        som?Data = "Initial data";
    }

    // St?p 3: Public static m?thod for instanc? acc?ss
    public static Singl?ton G?tInstanc?()
    {
        if (instanc? == null)
        {
            lock (syncRoot)
            {
                if (instanc? == null)
                {
                    instanc? = n?w Singl?ton();
                }
            }
        }

        r?turn instanc?;
    }

    // Oth?r m?thods and prop?rti?s of th? Singl?ton class
    public string G?tData()
    {
        r?turn som?Data;
    }

    public void S?tData(string data)
    {
        som?Data = data;
    }
}

public class Program
{
    public static void Main()
    {
        // G?t a r?f?r?nc? to th? Singl?ton instanc?.
        Singl?ton singl?ton1 = Singl?ton.G?tInstanc?();
        Singl?ton singl?ton2 = Singl?ton.G?tInstanc?();

        // Ch?ck if both r?f?r?nc?s point to th? sam? instanc?.
        if (singl?ton1 == singl?ton2)
        {
            Consol?.Writ?Lin?("Both r?f?r?nc?s point to th? sam? Singl?ton instanc?.");
        }
        ?ls?
        {
            Consol?.Writ?Lin?("Singl?ton patt?rn is brok?n; instanc?s ar? not th? sam?.");
        }

        // Us? th? Singl?ton instanc?.
        Consol?.Writ?Lin?("Data from Singl?ton: " + singl?ton1.G?tData());

        // Modify and r?tri?v? data.
        singl?ton1.S?tData("N?w data");
        Consol?.Writ?Lin?("Modifi?d data from Singl?ton: " + singl?ton2.G?tData());
    }
}

Output:

Output

Both r?f?r?nc?s point to th? sam? Singl?ton instanc?.
Data from Singl?ton: Initial data
Modifi?d data from Singl?ton: N?w data

Explanation:

Utilizing System: It serves as a crucial statement that grants access to various types and methods within the System namespace.

The public sealed class Singleton: This represents the Singleton class definition. It is marked as sealed to block inheritance, guaranteeing that no derived classes can be created.

The private static volatile Singleton instance is a private static variable instance utilized to store the single instance of the Singleton class. It is labeled as volatile to guarantee that alterations made by one thread are promptly visible to other threads.

The # Singleton Design pattern in C# keyword is utilized to define a unique instance of a class that can be accessed globally in a thread-safe manner.

The private Singleton constructor ensures that external code cannot create instances of the Singleton class using the new keyword. It enforces the single-instance rule.

The # Singleton Design pattern in C# method is a public static approach that grants entry to the Singleton instance. Within this function, it verifies if the instance is null. In case it is, a lock block is entered to guarantee that only one thread at a time generates the instance. This technique is referred to as double-check locking. Should the instance remain null while inside the lock, it generates the Singleton instance. This design guarantees the creation of a single instance even in a multi-threaded setting.

The method named GetData in the public scope enables retrieval of the data field from the Singleton instance.

This function enables you to update the som?Data field of the Singleton instance.

This Program class d?monstrat?s th? usag? of th? Singl?ton patt?rn:

  • It obtains two r?f?r?nc?s ( singl?ton1 and singl?ton2 ) to th? Singl?ton instanc? using Singl?ton.G?tInstanc? .
  • It ch?cks if both r?f?r?nc?s point to th? sam? Singl?ton instanc? . If th?y do, it prints a m?ssag? confirming th? Singl?ton patt?rn is working as ?xp?ct?d.
  • It us?s th? Singl?ton instanc? to r?tri?v? and modify th? data using th? G?tData and S?tData m?thods .

When you execute this program, you should see the output as depicted.

Compl?xity Analysis:

Tim? Compl?xity:

The time complexity of the Singleton pattern implementation typically remains at O(1), indicating a consistent time complexity. This is applicable to key operations:

Creation of Singleton Instance (GetInstance method): Developing the Singleton instance is an operation that maintains a consistent duration because it is executed only once during the application's runtime, regardless of the number of times GetInstance is called. The process within GetInstance includes a straightforward null verification and sometimes a synchronization mechanism for thread safety. These procedures are not influenced by the size of the information or the frequency of method invocations.

Accessing Data (GetData and SetData methods): Retrieving or updating information within the Singleton instance commonly has a time complexity of O(1). These functions directly interact with a class attribute (someData), which remains constant regardless of the input size or the frequency of method invocations.

Locking Mechanism: Introducing synchronization in the GetInstance method through the use of the lock statement ensures thread safety. The act of locking and subsequently releasing the lock is generally considered to have an O(1) time complexity. However, in situations with high concurrency, the time complexity may be impacted by thread contention. On average, the complexity remains stable.

Spac? Compl?xity:

The space complexity of the Singleton pattern implementation is likewise O(1), denoting consistent space usage. Key components include:

Creating a Singleton Instance: Maintaining the Singleton instance necessitates consistent space allocation. Irrespective of the frequency of GetInstance invocations, a singular instance is always present, ensuring a steady memory footprint.

Additional Information Members (e.g., someData): The space complexity related to extra data members inside the Singleton class is contingent upon their attributes. In the given code snippet, someData represents a string and its space complexity is influenced by the extent of the string. Typically, class fields exhibit a space complexity of O(1) unless they incorporate variable-sized collections or arrays.

Locking Mechanism (e.g., syncRoot): The space complexity associated with the syncRoot object utilized for synchronization remains constant. This object refers to a fixed-size entity, and its memory usage remains unchanged regardless of the input.

Input Required

This code uses input(). Please provide values below: