Introduction to Design Patterns and Power of Singleton Design Pattern

Damsak Bandara
6 min readMay 20, 2021

Standard Definition -

“A software design pattern is a general, reusable solution to a commonly occurring problem within a given context in software engineering”

Let’s try to understand this with a simple example.

Think about a situation where you go to the doctor. The doctor may ask few questions about your health. Then he may perform some tests. Now based on this the doctor may come to a conclusion and issue a treatment.

What really happened here?

The doctor identified a pattern based on your answers and historical records. Then he decided on the treatment.

This same scenario is applicable to the software designer. In the initial phases of the software development, we may see that we have a set of problems and we need a set of solutions. Some of the problems have been identified and solved previously in a proper well-accepted way and reusable manner. So we have the ability to use that particular solution as it is without trying to figure out a new way of solving it. Design patterns represent an idea, not an implementation.

So as mentioned, design patterns are basically the solutions to general problems that software developers face during the development. These solutions are well tested and proven. Design patterns were first introduced in 1994 by a book called “Design Patterns — Elements of Reusable Object-Oriented Software”. According to this book, design patterns are based on 2 principles of object-oriented design.

  • Program to an Interface, not an Implementation
  • Favor object composition over inheritance.

Uses of Design patterns

  • Design patterns can be used to speed up the development process. This is done by providing tested, proven, and reusable design solutions.
  • Improves code readability.
  • Makes the design resilient to change.
  • Easier to maintain.

Types of design patterns

There are 3 main categories of design patterns.

1. Creational Patterns

These patterns are concerned with the way of creating objects. That means the particular decision to be made at the instantiation time of the class. In other words, creational design patterns provide a path to create objects without exposing the creational logic. The overall flexibility of the program is increased.

Related Design patterns —

  1. Singleton Pattern
  2. Factory Method Pattern
  3. Abstract Factory Method Pattern
  4. Prototype Pattern
  5. Builder Pattern
  6. Object Pool Pattern

2. Structural Design Patterns

These patterns are concerned with how classes and objects can be composed in order to form larger structures. These classes composed while maintaining flexibility and efficiency. The main goal of structural design patterns is to simplify the structure by identifying the relationships among them.

Related Design patterns —

  1. Adapter Pattern
  2. Bridge Pattern
  3. Composite Pattern
  4. Decorator Pattern
  5. Facade Pattern
  6. Flyweight Pattern
  7. Proxy Pattern

3. Behavioral Design Patterns

These are the patterns that identify common communication patterns among objects. The primary goal is to increase flexibility in carrying out communication. That means the objects(implementation and client) should be loosely coupled.

Related Design patterns —

  1. Chain of Responsibility Pattern
  2. Command Pattern
  3. Interpreter Pattern
  4. Iterator Pattern
  5. Mediator Pattern
  6. Memento Pattern
  7. Null Object Pattern
  8. Observer Pattern
  9. State Pattern
  10. Strategy Pattern
  11. Template Method Pattern
  12. Visitor Pattern

Now let’s focus on one of the most commonly used Design patterns called the Singleton Design Pattern.

Singleton Design Pattern

This design pattern focuses on ensuring that a particular class(singleton class) can only have a single instance and provides a global point of access to it. That means only 1 instance is created(1 instance per JVM). This pattern saves memory which is the core advantage of using this pattern. Mostly used in multi-threaded and database applications.

During the usage of the Singleton class, we should always make sure to take no arguments when we create the instance. If we are to take arguments, it's always better to go for a factory Design Pattern.

Another important point to note is that the singleton class is harder to Unit test as there are no Instance variables or any other references. Therefore we should always analyze the requirements carefully and use this design pattern only when it is necessary.

Let’s try to understand the concepts of the Singleton Design pattern through a practical example.

Singleton Use case

There is a hotel network called Ceylon Travels and their office is located in Colombo. All of the computers in the office have the Ceylon travel system installed.

Now a new smart robot is added to the office which can deliver hardware files within the office in a predefined path. However, this robot can only deliver 1 request at a time. That means 2 employees cannot use this smart file delivering robot at the same time.

As the first step, let’s create a basic application with a singleton pattern ensuring that only a single robot class can be created.

Robot Manager class —

System main class —

Output —

From the above output it's clear to us that even though we have created 2 separate objects, the “robotManager” class only gave us the same instance.

However, this implementation limits our capability with the robotmanager class. Therefore let’s change the robotManager implementation as follows.

The Main class and the output of the application will be similar to the previous implementation.

In this implementation, the getManager() method will check for an instance of robotManager. If it is null, then a new robotManager object is created. if it is true, it will send the already created instance. So it's a better implementation.

But there is a problem with this implementation as well.

Problem with this Implementation

Consider the following edge case.

There are 2 threads coming from 2 applications of the Ceylon Travel system called thread A and Thread B.

  1. Thread A goes to the getManager method and checks the status. It's null because the robot was in an idle state.
  2. Therefore Thread A will go to the process of creating the robotManager instance.
  3. In this exact time(robotManager object is being created) Thread B will come to the getManager() method and check the status. It will still be null as there are no created robotManager Objects.
  4. Then this Thread B will also come inside the getManager() method.

Therefore this implementation is not Thread Safe. So to avoid that, we can use the double-checking Implementation. Let’s implement it as follows.

In this implementation, we have used the “synchronized” keyword to acquire the locks. Then we also check if the robotManager instance is null. This avoids the above-mentioned problem.

Note: “synchronized” keyword should not be used in the method declaration. It will create a huge performce loss in production level implementations.

Can the Singleton design pattern really make a difference?

Let’s try to find the answer to this question with the help of our discussed example.

Assumption: It will take 2 seconds (2000 milliseconds) for the creation of a new robot Manager instance(as in the real application it may have various processes and configurations to be done).

Let’s implement this behavior in the class using thread.sleep() method and calculate the time taken to get the 2 instances.

Robot manager class —

System main class —

Output —

Note: This the time to actually get the particular instance.

It took 2006 milliseconds ( 2 seconds and 6 milliseconds) to create the first instance.

However, in order to get the second instance, it took 0 seconds. That is because the instance is already created. Now our application is fast and the requirement is also complete (Only a single instance is available and can be accessed at a given time).

So it's clear that Singleton saved us almost 2 seconds in the above example.

The following Github link provides an enhanced version of the above application. This enhanced application assumes that the robot needs to do 2 configurations at the time of creation.

  • Configure Location
  • Configure Settings

I have used the following playlist by Mr.Krishntha Dinesh to gather the required information.

--

--