Singleton Design Pattern

Design Pattern Tutorial Series

Singleton Design Pattern in Java - 5-Step Guide

The Singleton Pattern is without a doubt the simplest, but also most powerful design patterns. It provides a one-way access to a class, which ensures that whenever this class is retrieved, that it will always be the same instance.

From a real-life perspective, we see this all the time. Whenever there is only one instance of a product (e.g. vacuum cleaner) and it was to be share with multiple people (e.g. room mates).

Although the singleton pattern is centered around retrieving a universal instance of a class, it also dictates when this instance has to be created. For this reason, the pattern is categorized as a creational design pattern.

Table of Contents

singleton-pattern-overview-integu

Step 1 - The Objective

The objective for this tutorial, will be discussing how a shared office space with many employees can share the same printer. This makes sense, since it is often the reality for corporations and companies with employees sharing office facilities.

 

In this case we do not have any secondary objectives, since we could easily solve the objective both with and without the singleton pattern. However, this is more about recognizing the natural behavior of the shared object and building the most appropriate and cleanest code to simulate this behavior.

singleton-pattern-objective-INTEGU

Step 2 - Distribution As An Object

Without the singleton pattern, we simply have a system with two types of objects: The printer- and the employee object.

The employee object contains the information, which we want to print. In order to print we ask the employee object to print.

However, for the employee object to print, it needs an instance of a printer. We do not provide each employee with their own instance of the printer, since that would not simulate the real scenario.

Instead we provide the printer as an argument for when we want the employee to print. Thereby we can limit the number of printer object instances to one contained in the main context of the system.

singleton-pattern-distribution-of-objects-INTEGU

 

public class Main {
    public static void main(String[] args) {
        Employee graham = new Employee("Graham",
                "CEO",
                "Making excutive decisions");
        Printer printer = new Printer();
        graham.printCurrentAssignment(printer);
    }
}

This way of solving the problem is totally fine and will not at this scale present any problem. However, being able to initialize the class from anywhere and having unnecessary arguments for any method will at scale become a problem in terms of maintenance and understanding the code.

Since we know that there is only one printer in the office, the public constructor becomes a dangerous opportunity for the system. What if a developer sits in another part of the code and do not have the printer object available? Well they could just initialize it and use it.

However, this means that we suddenly have two printer objects in the code, which does not reflect the real-world scenario. This may cause problems if we for example wanted to keep track of all pages printed by the single instance of the printer.

Let’s imagine that we one day in the future add another method to the employee class, which also requires a printer. Say this method allows the employee to print multiple copies of a given document, with appropriate names and titles for each employee for which it is intended for.

As we can see the methods can quickly expand its list of arguments. Some of these arguments makes sense to provide for this method specifically, but the printer object is not one of them. Zero arguments are the optimal number of arguments.

We know that there is only one printer available at the office, so is it really necessary to provide it as an argument. Let’s see how we can solve this problem by utilizing the singleton pattern.

graham.printCopiesOfDocumentForListOfEmp(printer, 
                   5, 
                   "Time schedule for the past five weeks"
                    listOfEmployees);

Step 3 - Concept of the Singleton Pattern

The concept of the singleton design pattern is based around a private constructor and a public static initialization method.

The private constructor ensures that the class can only be initialized by itself, which makes the public static initialization method the only way of getting an instance of the class.

However, we do not want the method to start a new instance for each time it is call. Therefore, we save the instance of the class in a static field inside its own class. Yep! This quickly got weird.

Now that we have an instance of the class ready to work with inside the class, we null check on it when we call the static initialization method. If the class has not previously been initialized, then we initialize it, otherwise we return our static field instance.

This means that there will always only be one instance of the class available, hence the singleton pattern.

singleton-pattern-advantage-INTEGU

Step 4 - Class Diagram (UML)

In terms of class diagram, the singleton pattern is not worth talking about. As you might have figured out by now, the singleton pattern is based around two methods inside the same class, which makes the class diagram simple to understand.

Thereby said, that if you understand the concept of the singleton pattern from the previous section, you should be ready to dive into the code.

 

INTEGU - singleton-class-diagram

Step 5 - Code (Java)

Given that code is sometimes difficult to learn through concepts and theory, I provide the code for the example.

Hopefully, this will be sufficient for you to learn to identify and implement the singleton pattern in your future endeavors as a software developer.

Printer

public class Printer {
    private static Printer printer;
    private int nrOfPages;
    private Printer() {
    }
    public static Printer getInstance() {
        return printer == null ? 
                printer = new Printer() : 
                printer;
    }
    public void print(String text){
        System.out.println(text +
                "n" + "Pages printed today " + ++nrOfPages +
                "n" + "---------");
    }
}

Employee

public class Employee {
    private final String name;
    private final String role;
    private final String assignment;
    public Employee(String name, String role, String assignment) {
        this.name = name;
        this.role = role;
        this.assignment = assignment;
    }
    public void printCurrentAssignment(){
        Printer printer = Printer.getInstance();
        printer.print("Employee: " + name + "n" +
                "Role: " + role + "n" +
                "Assignment: " + assignment + "n");
    }
}

How to use the Singleton Pattern

public class Main {
    public static void main(String[] args) {
        Employee graham = new Employee("Graham",
                "CEO",
                "Making excutive decisions");
        Employee sara = new Employee("Sara",
                "Consultant",
                "Consuting the company");
        Employee tim = new Employee("Tim",
                "Salesmen",
                "Selling the company's products");
        Employee emma = new Employee("Emma",
                "Developer",
                "Developing the latest mobile app.");
        graham.printCurrentAssignment();
        sara.printCurrentAssignment();
        tim.printCurrentAssignment();
        emma.printCurrentAssignment();
    }
}

 

Recommended Reading

Article

  • Theoretical walkthrough – Source Making – Blog
  • Practical walkthrough – Tutorialspoint – Blog
  • Practical walkthrough – Springframework Guru – Blog

Books

Video Tutorial 

  • Theoretical  (based on “Head-First: Design Patterns”) – Christopher Okhravi – YouTube
  • Practical – Derek Banas – YouTube

Tools

  • Camtasia – Used for illustrations – Camtasia

About

Hi, I'm the Author

My name is Daniel H. Jacobsen and I’m a dedicated and highly motivated software developer with a masters engineering degree within the field of ICT. 

I have through many years of constantly learning and adapting to new challenges, gained a well-rounded understanding of what it takes to stay up to date with new technologies, tools and utilities. 

The purpose of this blog is to share both my learnings and knowledge with other likeminded developers as well as illustrating how these topics can be taught in a different and alternative manner.

If you like the idea of that, I would encourage you to sign up for the newsletter.

Cheers! 🍺

Didn't Find What You Were Looking For?

Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages
Scroll to Top