Singleton

Summary:  Ensure a class has only one instance and provide a global point of access to it.
Frequency of use:
Medium high

UML class diagram

Participants

The classes and objects participating in this pattern are:

  • Singleton   (LoadBalancer)
    • defines an Instance operation that lets clients access its unique instance. Instance is a class operation.
    • responsible for creating and maintaining its own unique instance.

Structural code in C#

This structural code demonstrates the Singleton pattern which assures only a single instance (the singleton) of the class can be created.

     

using System;

 

namespace DoFactory.GangOfFour.Singleton.Structural

{

  /// <summary>

  /// MainApp startup class for Structural

  /// Singleton Design Pattern.

  /// </summary>

  class MainApp

  {

    /// <summary>

    /// Entry point into console application.

    /// </summary>

    static void Main()

    {

      // Constructor is protected -- cannot use new

      Singleton s1 = Singleton.Instance();

      Singleton s2 = Singleton.Instance();

 

      // Test for same instance

      if (s1 == s2)

      {

        Console.WriteLine("Objects are the same instance");

      }

 

      // Wait for user

      Console.ReadKey();

    }

  }

 

  /// <summary>

  /// The 'Singleton' class

  /// </summary>

  class Singleton

  {

    private static Singleton _instance;

 

    // Constructor is 'protected'

    protected Singleton()

    {

    }

 

    public static Singleton Instance()

    {

      // Uses lazy initialization.

      // Note: this is not thread safe.

      if (_instance == null)

      {

        _instance = new Singleton();

      }

 

      return _instance;

    }

  }

}

Output
Objects are the same instance

Real-world code in C#

This real-world code demonstrates the Singleton pattern as a LoadBalancing object. Only a single instance (the singleton) of the class can be created because servers may dynamically come on- or off-line and every request must go throught the one object that has knowledge about the state of the (web) farm.

    

using System;

using System.Collections.Generic;

using System.Threading;

 

namespace DoFactory.GangOfFour.Singleton.RealWorld

{

  /// <summary>

  /// MainApp startup class for Real-World

  /// Singleton Design Pattern.

  /// </summary>

  class MainApp

  {

    /// <summary>

    /// Entry point into console application.

    /// </summary>

    static void Main()

    {

      LoadBalancer b1 = LoadBalancer.GetLoadBalancer();

      LoadBalancer b2 = LoadBalancer.GetLoadBalancer();

      LoadBalancer b3 = LoadBalancer.GetLoadBalancer();

      LoadBalancer b4 = LoadBalancer.GetLoadBalancer();

 

      // Same instance?

      if (b1 == b2 && b2 == b3 && b3 == b4)

      {

        Console.WriteLine("Same instance\n");

      }

 

      // Load balance 15 server requests

      LoadBalancer balancer = LoadBalancer.GetLoadBalancer();

      for (int i = 0; i < 15; i++)

      {

        string server = balancer.Server;

        Console.WriteLine("Dispatch Request to: " + server);

      }

 

      // Wait for user

      Console.ReadKey();

    }

  }

 

  /// <summary>

  /// The 'Singleton' class

  /// </summary>

  class LoadBalancer

  {

    private static LoadBalancer _instance;

    private List<string> _servers = new List<string>();

    private Random _random = new Random();

 

    // Lock synchronization object

    private static object syncLock = new object();

 

    // Constructor (protected)

    protected LoadBalancer()

    {

      // List of available servers

      _servers.Add("ServerI");

      _servers.Add("ServerII");

      _servers.Add("ServerIII");

      _servers.Add("ServerIV");

      _servers.Add("ServerV");

    }

 

    public static LoadBalancer GetLoadBalancer()

    {

      // Support multithreaded applications through

      // 'Double checked locking' pattern which (once

      // the instance exists) avoids locking each

      // time the method is invoked

      if (_instance == null)

      {

        lock (syncLock)

        {

          if (_instance == null)

          {

            _instance = new LoadBalancer();

          }

        }

      }

 

      return _instance;

    }

 

    // Simple, but effective random load balancer

    public string Server

    {

      get

      {

        int r = _random.Next(_servers.Count);

        return _servers[r].ToString();

      }

    }

  }

}

Output
Same instance

ServerIII
ServerII
ServerI
ServerII
ServerI
ServerIII
ServerI
ServerIII
ServerIV
ServerII
ServerII
ServerIII
ServerIV
ServerII
ServerIV

.NET Optimized code in C#


The .NET optimized code demonstrates the same code as above but uses more modern, built-in .NET features.

Here is an elegant .NET specific solution. The Singleton pattern simply uses a private constructor and a static readonly instance variable that is lazily initialized. Thread safety is guaranteed by the compiler.

     

using System;

using System.Collections.Generic;

 

namespace DoFactory.GangOfFour.Singleton.NETOptimized

{

  /// <summary>

  /// MainApp startup class for .NET optimized

  /// Singleton Design Pattern.

  /// </summary>

  public class MainApp

  {

    /// <summary>

    /// Entry point into console application.

    /// </summary>

    static void Main()

    {

      var b1 = LoadBalancer.GetLoadBalancer();

      var b2 = LoadBalancer.GetLoadBalancer();

      var b3 = LoadBalancer.GetLoadBalancer();

      var b4 = LoadBalancer.GetLoadBalancer();

 

      // Confirm these are the same instance

      if (b1 == b2 && b2 == b3 && b3 == b4)

      {

        Console.WriteLine("Same instance\n");

      }

 

      // Next, load balance 15 requests for a server

      var balancer = LoadBalancer.GetLoadBalancer();

      for (int i = 0; i < 15; i++)

      {

        string serverName = balancer.NextServer.Name;

        Console.WriteLine("Dispatch request to: " + serverName);

      }

 

      // Wait for user

      Console.ReadKey();

    }

  }

 

  /// <summary>

  /// The 'Singleton' class

  /// </summary>

  public sealed class LoadBalancer

  {

    // Static members are 'eagerly initialized', that is,

    // immediately when class is loaded for the first time.

    // .NET guarantees thread safety for static initialization

    private static readonly LoadBalancer _instance =

      new LoadBalancer();

 

    // Type-safe generic list of servers

    private List<Server> _servers { get; set; }

    private Random _random = new Random();

 

    // Note: constructor is 'private'

    private LoadBalancer()

    {

      // Load list of available servers

      _servers = new List<Server>

        {

         new Server{ Name = "ServerI", Ip = "120.14.220.18" },

         new Server{ Name = "ServerII", Ip = "120.14.220.19" },

         new Server{ Name = "ServerIII", Ip = "120.14.220.20" },

         new Server{ Name = "ServerIV", Ip = "120.14.220.21" },

         new Server{ Name = "ServerV", Ip = "120.14.220.22" },

        };

    }

 

    public static LoadBalancer GetLoadBalancer()

    {

      return _instance;

    }

 

    // Simple, but effective load balancer

    public Server NextServer

    {

      get

      {

        int random = _random.Next(_servers.Count);

        return _servers[random];

      }

    }

  }

 

  /// <summary>

  /// Represents a server machine

  /// </summary>

  public class Server

  {

    // Gets or sets server name

    public string Name { get; set; }

 

    // Gets or sets server IP address

    public string Ip { get; set; }

  }

}

Output

Same instance

ServerIV
ServerIV
ServerIII
ServerV
ServerII
ServerV
ServerII
ServerII
ServerI
ServerIV
ServerIV
ServerII
ServerI
ServerV
ServerIV




Stay Inspired!
Join other developers and designers who have already signed up for our mailing list.
Terms     Privacy     Licensing       EULA       Sitemap      
© Data & Object Factory, LLC.
Made with    in Austin, Texas