Java singleton pattern
Introduction
With this part of the Java patterns project, I provide implementations of the singleton design pattern in Java.
In what follows, I give an overview of sound and faulty implementations of this design pattern.
For general information about the singleton design pattern, refer to the Singleton section of the Patterns readme.
1. Implementations
There are two common ways to implement the singleton design pattern in Java, using a private constructor and using an enum.
1.1 A class with a private constructor
The first singleton implementation I discuss relies on a private
constructor, a static
instance and a static
method for retrieving this instance.
The file Singleton.java contains an abstract version of such a singleton implementation:
package nl.mauritssilvis.patterns.java.singleton.hide.general;
public final class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
Unit tests verify the singleton nature of the above class.
I used eager initialization of the singleton instance to guarantee thread safety without additional checks.
Additionally, the keyword final
is only applied to the class to remind us that extending a class with a private constructor is impossible.
This keyword is not essential for the singleton pattern.
A specific singleton implementation that makes use of a private constructor and that represents a global configuration class is provided by the file Configuration.java.
1.2 An enum
Another Java implementation of the singleton design pattern benefits from the property that enum
values are unique.
An abstract version of such an implementation is given by another file called Singleton.java:
package nl.mauritssilvis.patterns.java.singleton.enumerate.general;
public enum Singleton {
INSTANCE
}
Again, unit tests verify that an enum
forms a valid implementation of the singleton pattern.
A specific singleton implementation of the enum
type is given by Configuration.java.
2. Faulty implementations
Next to sound singleton pattern implementations, one can encounter classes that may look like but, strictly speaking, are not singletons.
2.1 A class with a protected constructor
A particular example of a faulty singleton implementation is given by classes using a protected
constructor.
Although protected
constructors serve the purpose of making class extension possible, they also allow child classes and classes that are part of the same package to instantiate additional objects.
An abstract version of a faulty singleton implementation is given by the file NoSingleton.java:
package nl.mauritssilvis.patterns.java.singleton.protect.general;
public class NoSingleton {
private static final NoSingleton INSTANCE = new NoSingleton();
protected NoSingleton() {
}
public static NoSingleton getInstance() {
return INSTANCE;
}
}
Unit tests verify that child classes and classes within the same package can create additional class instances.
License
Copyright © 2022, 2023 Maurits Silvis
This source code package is subject to the terms and conditions defined in the GNU General Public License v3.0 or later.