Your Guide to Design Patterns – Singleton Pattern

Design pattern - Singleton pattern

In this week’s tip, we’ll look at the Singleton design pattern. It’s one of the simplest to understand, Most books start by examining this pattern, similar to Java books which start with the “Hello, world!” program.

Singleton Pattern as a Creational Pattern

Remember that the GoF identified three types of patterns – creational, structural and behavioural.

The Singleton is a creational pattern. These patterns deal with the best way to create instances of objects. Our programs can be more flexible and reusable if we isolate the details of the creational process into a “creator” class.

Singleton Pattern: Intent

Patterns are generally described by a number of important parameters: name, motivation, intent and applicability (what it does, which problem it solves, where it can be used), consequences (what are the trade-offs from using a particular pattern), participants, collaborations, implementation, etc.

It is important to know the intent of a pattern. The intent of the Singleton design pattern is to ensure that only one instance of a class is created. It provides a global point of access to this instance object. It is occasionally important that a class has only one instance. We would probably only have one event logger, one print spooler, one identification number generator, one invoice generator, etc.

Singleton Pattern: EventLogger Example

The classic example of the Singleton design pattern is logging, so let’s create a simple event logging class. It will have a number of logging methods for different types of events, but this aspect of the class is not important from the point of view of implementing the Singleton pattern.

public class EventLogger {
   public void info(String message);
   public void warning(String message);
   public void error(String message);
   public void log(String message);
}

If we need only one instance of the EventLogger in our application, one option would be to create a global variable and assign an instance of the EventLogger to it. Creating a global variable is convenient if the programming language allows it (Java doesn’t). We would need to define rules for creating and using the global variable. These rules are difficult to enforce, and easy to get around. We should rather create a language mechanism to enforce this access.

The better solution is to use the Singleton design pattern. It has advantages over merely declaring a global variable. The Singleton pattern is conceptually very simple, and easy to code. Typically we would add just five or six statements to an existing Java class.

To turn a class into a singleton, we must do the following:

  1. Mark the constructor of the class as private. This prevents any clients from directly creating instances of the class.
  2. Create a private static reference to an object of the class type.
  3. Create a public static getInstance() method to the class. This method returns an instance of the class. The first time getInstance() is called, an instance of the class is created, cached and returned. When the getInstance() method is subsequently called, the cached instance is returned.

Let’s see this in code:

public class EventLogger {

   private static EventLogger instance;  // cached reference

   public static EventLogger getInstance() {
      if (instance == null)
      instance = new EventLogger(); // lazy instantiation
      return instance;
   }

   private EventLogger() {
      // appropriate code
   }    
    // all other normal logging methods
}

We would use this code as follows:

...
EventLogger logger = EventLogger.getInstance();
logger.log("Some message");
...

Thread-safe Singletons

We need to ensure that getInstance() is thread-safe if we’re using this class in a multi-threaded application. We can add the synchronized keyword to the getInstance() method to make it thread-safe.

Synchronized methods are much slower than non-synchronized ones. However, unless getInstance() is called repeatedly, the overhead will be negligible.

If the singleton will always be needed in the application, we can create the object instance at startup, and have a non-synchronized getInstance() method as follows:

public class EventLogger {

   // eager instantiation
   private static EventLogger instance  = new EventLogger(); 
   public static EventLogger getInstance() {
       return instance;
   }

   private EventLogger() {
       // appropriate code
   }

   // all other normal logging methods
}

The Java runtime guarantees that static class variables are initialized before they are accessible from any thread. Just remember that any data needed to initialize the instance must be available during static initialization.

Enum Singleton Example

The previous code is the “traditional” approach to coding singletons. Java has an enum class which makes it much easier to code thread-safe singletons. The enum constructor is implicitly private. An example follows:

public enum EventLogger {
   INSTANCE;  // that's it!    
   // all other normal logging methods
}

We use this code as follows:

EventLogger.INSTANCE.log("Some message");

Internally enums consist of static class variables, which we now know are guaranteed to be initialized before they are accessible from any thread.

What’s next?

In the weeks ahead, we’ll look at the more useful design patterns. Stay tuned!

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.