| Lesson 9 | Singleton: known uses |
| Objective | Explore Real World Examples of the Singleton Design Pattern. |
In practice, “Singleton” usually means exactly one instance per application boundary. The boundary matters: a single JVM, a single Node.js process, a single desktop app process, or a single service instance in a container. If your deployment runs multiple processes (Node cluster, Kubernetes replicas, Windows services across multiple hosts), you do not automatically get “one instance globally”—you get one instance per process.
Use Singleton when you truly need a single coordinator for a shared resource (serialization, caching, or shared configuration). Avoid it when it becomes a disguised global variable that spreads hidden dependencies.
A logger is a classic Singleton candidate because it brokers access to an append-only destination (file, stdout, syslog, remote log sink). The goal is consistent formatting, consistent metadata (request id, user id), and serialized writes to avoid interleaving. In many ecosystems, the “singleton” is owned by the logging framework (for example, a global logger registry).
Applications frequently load configuration once (environment variables, config files, secret managers) and provide a stable read interface. The same pattern appears in feature-flag clients (LaunchDarkly-style SDKs, internal toggles): one client instance, shared cache, periodic refresh, and a single place to manage credentials and lifecycle.
Telemetry libraries commonly expose a process-wide registry for counters, gauges, histograms, and tracing providers. One registry prevents duplicated metrics names and ensures consistent labeling across the codebase.
Database clients, HTTP clients, and connection pools are often instantiated once and reused. This is less about “one instance because pattern” and more about efficient resource reuse, throttling, and consistent retry/backoff policies.
A shared cache (LRU cache, memoization store, compiled-regex cache) is commonly centralized to avoid duplicate memory usage and to coordinate eviction strategy.
In Node.js, the most common “Singleton” is simply a module export.
The first import/require constructs the object; subsequent imports receive the cached instance (per process).
This is usually preferable to a manual getInstance() because it aligns with the platform’s module system.
// configManager.js (CommonJS)
class ConfigManager {
constructor() {
// Example: initialize once from environment, file, secret manager, etc.
this.config = Object.freeze({
appName: process.env.APP_NAME || "gofpattern",
logLevel: process.env.LOG_LEVEL || "info"
});
}
get(key) {
return this.config[key];
}
}
module.exports = new ConfigManager();
// usage.js
const config = require("./configManager");
console.log(config.get("logLevel"));
public enum AppConfig {
INSTANCE;
private final java.util.Properties props = new java.util.Properties();
AppConfig() {
// Load once (file, classpath resource, env, etc.)
props.setProperty("logLevel", System.getProperty("logLevel", "INFO"));
}
public String get(String key) {
return props.getProperty(key);
}
}
#include <string>
class Logger {
public:
static Logger& instance() {
static Logger inst; // initialized once, thread-safe (C++11+)
return inst;
}
void log(const std::string& msg) {
// write to sink
}
private:
Logger() = default;
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
};
In both cases, treat Singleton as a lifecycle-managed service: define initialization rules, provide a clean shutdown path when required, and avoid hiding important dependencies.
Use Singleton when:
Prefer alternatives when:
Many classic libraries contain objects that behave like singletons: global registries, session managers, GUI toolkits, and system services. Some historical examples referenced in older literature may point to internal or non-public APIs; treat those as illustrative rather than prescriptive.
Once you recognize the intent—“single shared instance with controlled access”—you will see it frequently. The key is to apply it deliberately: keep state minimal, document lifecycle, and avoid turning Singleton into a convenient hiding place for unrelated responsibilities.