Simple explanation for Singleton Pattern
Situation: You’re Creating a Database Connection Manager
You need to connect your application to a database.
Simple. You write:
DatabaseConnection conn = new DatabaseConnection();
All cool.
Then Problems Start
- Different parts of your app start creating their own separate connections.
- You realize each connection is expensive (memory, network sockets, auth).
- Worse: two objects might not even know they’re working with different connections - leading to weird bugs like dirty reads, locks, race conditions.
Now you’re stuck debugging issues that feel random but are actually because you have multiple instances of something that should have been only one.
What’s the Real Problem?
- Multiple instances of something that should be shared.
- Waste of resources (DB, memory, network).
- Inconsistent behavior across your app.
- Testing and debugging becomes confusing.
How Singleton Pattern Saves You
Singleton says: “Dude, there should be exactly ONE object of this class - ever. And everyone should share it.”
So you:
- Create the instance once.
- Reuse it everywhere.
- Control access through a single global point.
This way:
- Only one connection is open.
- Everyone uses the same setup/config.
- Behavior stays consistent.
class DatabaseConnection {
private static DatabaseConnection instance;
private DatabaseConnection() {
System.out.println("Connecting to database...");
}
public static synchronized DatabaseConnection getInstance() {
if (instance == null) {
instance = new DatabaseConnection();
}
return instance;
}
public void query(String sql) {
System.out.println("Running query: " + sql);
}
}
When to Use Singleton?
- When only one instance should ever exist (e.g., Database Connection, Logger, Config Manager, Thread Pool Manager).
- When global shared access is needed.
- When managing resources carefully matters.