Other Parts of This Series:


Singleton Design Pattern (Photo Credit: refactoring.guru)

Singleton Design Pattern (Photo Credit: refactoring.guru)

In this series, we try to explore software design patterns and principles. We will try to learn the well-known OOP design patterns one by one. In this part, we try to explore the singleton design pattern.

So let’s get started…


Story

Ismael is a very good boy and over 21 years old. As he is an adult now, he decided to marry someone and addressed him as my wife. As I previously stated, he is a good boy (though, like other men, he also has petty thinking), and he desires only one wife in his entire life. So he is looking for a wife until he finds someone to be his wife. When he found someone, he left his entire life with her and refused to accept any other girls as his wife.

Now he is in search of his singleton wife.

Singleton Design Pattern

Singleton Design Pattern (Photo Credit: refactoring.guru)

Singleton Design Pattern (Photo Credit: refactoring.guru)

The singleton design pattern is a creational design pattern that helps us to create and maintain only one instance of a class. That is, as its name refers, the singleton design pattern gives us a way to create only one instance object of a class and ensure the use of this object everywhere in the system.

Like the Ismael in the above story, he allows the first woman as his wife; after that, he refuses the other instances of women as his wife.

Problems The Singleton Design Pattern Solves:

We know every design pattern is meant to solve some design problems; the singleton design pattern also solves 2 problems. Like:

  1. Ensures that a class has just only one single instance object.
  2. Provide a global access point to that instance.

Singleton Design Pattern Applicability:

  • Use the Singleton pattern when a class in your program should have just a single instance available to all clients; for example, a single database object shared by different parts of the program or a logger for log systems’ different messages.
  • Use the Singleton pattern when you need stricter control over global variables.

UML Diagram:

Singleton Design Pattern UML (Photo Credit: tutorialspoint.com)

Singleton Design Pattern UML (Photo Credit: tutorialspoint.com)

You can see in the above UML diagram that every time a caller requests an instance, it returns the already created instance.

Implementation

Java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package sir.singleton.example.thread_safe;

public final class Wife {

    private static volatile Wife wife;
    public int counter = 0;

    private Wife () {
        this.counter++;
    }

    public static Wife getInstance() {
        Singleton result = wife;
        if (result != null) {
            return result;
        }
        synchronized(Wife.class) {
            if (wife == null) {
                wife = new Wife();
            }
            return wife;
        }
    }
}

// Caller
public class DemoMultiThread {
    public static void main(String[] args) {
        Thread threadFoo = new Thread(new ThreadFoo());
        Thread threadBar = new Thread(new ThreadBar());
        threadFoo.start();
        threadBar.start();
    }

    static class ThreadFoo implements Runnable {
        @Override
        public void run() {
            Wife wife = Wife.getInstance();
            System.out.println(wife.counter);
        }
    }

    static class ThreadBar implements Runnable {
        @Override
        public void run() {
            Wife wife = Wife.getInstance();
            System.out.println(wife.counter);
        }
    }
}

C#:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using System;

namespace SingletonDesignPattern
{
    sealed class Wife
    {
        // Step 1: Create a single, readonly instance at class load time
        private static readonly Wife instance = new Wife();

        // Step 2: Track number of instances (should always be 1)
        public static int NumberOfInstance { get; private set; }

        // Step 3: Private constructor prevents external instantiation
        private Wife()
        {
            NumberOfInstance++;
            Console.WriteLine("Wife instance created.");
        }

        // Step 4: Provide a global access point
        public static Wife Instance
        {
            get { return instance; }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Access singleton instance
            Wife wife1 = Wife.Instance;
            Console.WriteLine($"Number of instances: {Wife.NumberOfInstance}");

            // This line would cause a compile-time error because the constructor is private
            // Wife obj = new Wife(); 

            Wife wife2 = Wife.Instance;
            Console.WriteLine($"Number of instances: {Wife.NumberOfInstance}");

            // Confirm both references point to the same instance
            Console.WriteLine($"Are wife1 and wife2 same instance? {ReferenceEquals(wife1, wife2)}");
        }
    }
}

The above implementation is fine and simple enough, but here is a problem when we are working on a multithread. Because in the multithread system we can’t guarantee 100% that only one instance will be created because more than 1 thread can access the class simultaneously and create multiple instances of the class and break the singleton rule. So we have a thread-safe implementation of the singleton design pattern as below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using System;
using System.Threading;

namespace SingletonDesignPattern
{
    class Wife
    {
        private Wife() { }

        private static Wife _instance;
        private static readonly object _lock = new object();

        public static Wife GetInstance(string value)
        {
            if (_instance == null)
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = new Wife();
                        NumberOfInstance++;
                        Console.WriteLine($"Wife instance created with value: {value}");
                    }
                }
            }
            return _instance;
        }

        public static int NumberOfInstance { get; private set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Thread process1 = new Thread(() =>
            {
                TestSingleton("First");
            });

            Thread process2 = new Thread(() =>
            {
                TestSingleton("Second");
            });

            process1.Start();
            process2.Start();

            process1.Join();
            process2.Join();

            Console.WriteLine($"Total number of Wife instances created: {Wife.NumberOfInstance}");
        }

        static void TestSingleton(string value)
        {
            Wife singleton = Wife.GetInstance(value);
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} got instance hash: {singleton.GetHashCode()}");
        }
    }
}

Points To Remember About Singleton:

  • Use singleton pattern when your system need only one instance of a class to all its clients.
  • Use singleton when you need stricter control over global variables.
  • When implementing singleton pattern, multithreaded scenario keeps in mind always.