Lesson 1
Singleton Pattern
Introduction to Creational Patterns

Welcome! Let's start our journey with an essential creational design pattern: the Singleton pattern. Creational patterns are designed to manage object creation in a way that promotes flexibility and reusability in your code. The Singleton pattern, in particular, is useful when you need to ensure that a class has only one instance and provides a global point of access to it.

The Singleton Pattern

In this lesson, you'll dive into the following key aspects of the Singleton pattern:

  • Understand the purpose and use cases for the Singleton pattern.
  • Learn how to implement the Singleton pattern using the Bill Pugh Singleton implementation in Java.
  • See how a Singleton instance can be accessed globally.
  • Understand the key parts of the Singleton implementation:
    • Private Constructor: To prevent instantiation from other classes.
    • Static Inner Class: To hold the Singleton instance, providing lazy-loaded, thread-safe initialization.
    • Public getInstance() Method: To provide global access to the Singleton instance.

We'll guide you step by step using the provided example code, so you can see how this pattern works in practice.

Understanding the Singleton Pattern

The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance. It is particularly useful in scenarios where a single object must coordinate actions across a system. For example, you might use a Singleton for managing configurations or logging activities.

We'll be using the Bill Pugh Singleton implementation, which is both lazy-loaded and thread-safe:

  • Lazy-loading: This means that the Singleton instance is not created until it is first needed, which can save resources and increase efficiency.
  • Thread-safety: This ensures that even in multi-threaded environments, there is no risk of creating multiple instances of the Singleton.

We'll guide you step by step using the following section, so you can see how this pattern works in practice!

Step 1: Define the Singleton Class and Create a Private Constructor

First, define the Singleton class. The private constructor prevents other classes from instantiating the Singleton class directly, ensuring that only one instance of the class can ever be created.

Java
1public class Singleton { 2 // Private constructor to prevent instantiation from other classes 3 private Singleton() { 4 // Initialization code here 5 }
Step 2: Define a Static Inner Helper Class

The static inner helper class holds the Singleton instance. This class is loaded only when it is referenced for the first time, ensuring that the Singleton instance is created in a thread-safe and lazy-loaded manner.

Java
1 // Static inner helper class that holds the Singleton instance 2 private static class SingletonHelper { 3 // The Singleton instance is created when this class is loaded 4 private static final Singleton INSTANCE = new Singleton(); 5 }
Step 3: Provide a Public getInstance() Method

The public getInstance() method provides a global point of access to the Singleton instance. It returns the instance held by the SingletonHelper class.

Java
1 // Public method to provide access to the Singleton instance 2 public static Singleton getInstance() { 3 return SingletonHelper.INSTANCE; 4 }
Step 4: Add Example Method

The example method showMessage() demonstrates how to use the Singleton instance. In this case, it simply prints a message to the console, indicating that the Singleton instance is in use.

Java
1 // Example method for demonstration purposes 2 public void showMessage() { 3 System.out.println("Hello from the Singleton instance!"); 4 } 5}
Accessing the Singleton Instance

Here's a simple main method to demonstrate how to access the Singleton instance:

Java
1public class Main { 2 public static void main(String[] args) { 3 Singleton singleton = Singleton.getInstance(); 4 singleton.showMessage(); 5 } 6}
Singleton Pattern Principles

To make sure correct Singleton pattern implementation, you need to adhere to the following main principles:

  • Ensure that only one instance of the class exists per JVM.
  • Provide a global access point to that instance.
  • Make the constructor private to prevent other classes from instantiating the class directly.
  • Use a static inner helper class to hold the Singleton instance, ensuring thread-safe lazy initialization.
Importance of the Singleton Pattern

The Singleton pattern is important because it helps you manage shared resources more efficiently. For example, think of scenarios like logging, configuration settings, or database connections — these are areas where you typically need only one instance. By using the Singleton pattern, you can avoid the complexity and potential errors associated with multiple instances.

Common usage scenarios include:

  • Logging services
  • Driver objects (e.g., printers or database connections)
  • Thread pools

Additionally, the Singleton pattern is often used when implementing other design patterns, such as Abstract Factory, Builder, and Prototype patterns.

Exciting, right? The Singleton pattern not only simplifies your code but also makes it more efficient and easier to manage. Let's jump into the practice section and start applying what we've learned!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.