Card 03/ 09
Singleton Template in Python, Java and TypeScript
A lazily created instance, and the Java enum form that is safe across threads.
The Singleton template is the pattern in its pure form: a class that creates its one instance the first time it is asked, and returns that instance on every call after. Each language enforces the single instance to a different degree, and in Java the simple form has a problem with threads, so the Java listing ends on the form Java developers are advised to use instead.
Building the template one part at a time
The field
A class attribute holds the instance, empty until the first request.
class Singleton:
_instance: Optional["Singleton"] = NoneThe access point
A class method creates the instance on the first call and returns it on every call.
@classmethod
def instance(cls) -> "Singleton":
if cls._instance is None:
cls._instance = cls()
return cls._instanceThe client
Every caller asks the class, never the constructor.
first = Singleton.instance()
second = Singleton.instance()The complete template
from typing import Optional
class Singleton:
_instance: Optional["Singleton"] = None
def __init__(self) -> None:
print("creating the one instance")
self.calls = 0
@classmethod
def instance(cls) -> "Singleton":
if cls._instance is None:
cls._instance = cls()
return cls._instance
first = Singleton.instance()
second = Singleton.instance()
first.calls += 1
second.calls += 1
print("same object:", first is second)
print("calls seen through either name:", Singleton.instance().calls)creating the one instance
same object: True
calls seen through either name: 2public class SgTemplate {
public static void main(String[] args) {
Singleton first = Singleton.getInstance();
Singleton second = Singleton.getInstance();
System.out.println("lazy form, same object: " + (first == second));
Registry.INSTANCE.register("orders");
Registry.INSTANCE.register("invoices");
System.out.println("enum form, names: " + Registry.INSTANCE.names());
}
}
class Singleton {
private static Singleton instance;
private Singleton() {
System.out.println("creating the one instance");
}
static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
enum Registry {
INSTANCE;
private final java.util.List<String> names = new java.util.ArrayList<>();
void register(String name) { names.add(name); }
java.util.List<String> names() { return names; }
}creating the one instance
lazy form, same object: true
enum form, names: [orders, invoices]class Singleton {
private static instance: Singleton | undefined;
calls = 0;
private constructor() {
console.log("creating the one instance");
}
static getInstance(): Singleton {
if (Singleton.instance === undefined) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
const first = Singleton.getInstance();
const second = Singleton.getInstance();
first.calls += 1;
second.calls += 1;
console.log("same object:", first === second);
console.log("calls seen through either name:", Singleton.getInstance().calls);creating the one instance
same object: true
calls seen through either name: 2In each language "creating the one instance" prints once, the two names refer to the same object, and both increments land on it, so either name sees a count of 2. The guarantee differs. TypeScript and Java refuse a call to the private constructor from outside the class at compile time. Python has no private constructor, so its singleton holds only as long as callers use instance().
The lazy Java form is not safe when two threads call getInstance() at once: both can find instance empty and both create one. That race is described here rather than shown, because its output depends on timing and may not repeat. The enum form avoids it, since the JVM creates an enum's constants exactly once, when the class is first used, and it also survives serialisation, which the lazy form does not. Joshua Bloch recommends it in Effective Java, item 3, as the best way to write a singleton in Java.
← → move through sections and cards