What is the use of making constructor private in a class?
Categories:
The Power of Private Constructors: Controlling Object Creation

Explore the strategic reasons behind making a class constructor private, from enforcing singletons to managing object pools and preventing direct instantiation.
In object-oriented programming, constructors are special methods used to initialize new objects of a class. Typically, constructors are declared public, allowing any part of the code to create instances of the class. However, there are specific scenarios where making a constructor private offers significant advantages, enabling stricter control over object creation and enforcing design patterns. This article delves into the various uses and benefits of private constructors, providing practical examples and insights into their application.
Enforcing the Singleton Design Pattern
One of the most common and powerful uses of a private constructor is to implement the Singleton design pattern. The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance. By making the constructor private, you prevent external code from directly instantiating the class. Instead, the class itself controls the creation and retrieval of its sole instance through a public static method.
classDiagram class Singleton { -Singleton instance -Singleton() +static Singleton getInstance() +doSomething() } Client --> Singleton : uses
Class diagram illustrating the Singleton pattern with a private constructor.
public class Singleton {
private static Singleton instance;
// Private constructor to prevent direct instantiation
private Singleton() {
// Initialization code
}
// Public static method to get the single instance
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public void showMessage() {
System.out.println("Hello from Singleton!");
}
}
// Usage:
// Singleton s1 = Singleton.getInstance();
// Singleton s2 = Singleton.getInstance();
// System.out.println(s1 == s2); // true
Java example of a Singleton class using a private constructor.
synchronized
keyword or Double-Checked Locking
) to ensure thread safety during instance creation.Preventing Instantiation of Utility Classes
Utility classes (also known as helper or static classes) often contain only static methods and fields, providing common functionalities without requiring an object instance. Examples include java.lang.Math
or java.util.Collections
. If such a class is not meant to be instantiated, making its constructor private explicitly communicates this intent and prevents accidental or erroneous object creation. This ensures that all interactions with the class occur through its static members.
public static class MathUtils // In C#, 'static class' implicitly has a private constructor
{
public static double Add(double a, double b)
{
return a + b;
}
public static double Subtract(double a, double b)
{
return a - b;
}
}
// In Java, you'd explicitly make the constructor private:
/*
public class StringUtils {
private StringUtils() { // Private constructor
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
public static boolean isNullOrEmpty(String str) {
return str == null || str.isEmpty();
}
}
*/
C# example of a static utility class (implicitly private constructor) and a Java equivalent with an explicit private constructor.
Controlling Object Creation in Factory Methods and Object Pools
Private constructors are fundamental when you want to delegate object creation to a factory method or manage objects within an object pool. In these scenarios, the class itself (or a designated factory class) is responsible for creating instances, often based on specific parameters or resource availability. External code requests objects from the factory or pool, which then uses the private constructor internally to create or retrieve an appropriate instance. This pattern centralizes creation logic, allowing for more complex instantiation processes, caching, or resource management.
flowchart LR Client -- "request object" --> Factory Factory -- "new MyObject()" --> MyObject(MyObject (private constructor)) Factory -- "return object" --> Client
Flowchart demonstrating object creation via a Factory method using a private constructor.
class DatabaseConnection:
_instances = {}
def __new__(cls, db_name):
if db_name not in cls._instances:
# Use super().__new__ to create the actual object
instance = super().__new__(cls)
instance._db_name = db_name
cls._instances[db_name] = instance
return cls._instances[db_name]
# The __init__ method is effectively the constructor, but __new__ controls instance creation
def __init__(self, db_name):
# This will be called every time, but __new__ ensures only one instance per db_name
if not hasattr(self, '_initialized'):
print(f"Initializing connection to {db_name}")
self._initialized = True
def connect(self):
print(f"Connecting to database: {self._db_name}")
# Usage:
# conn1 = DatabaseConnection("mydb")
# conn2 = DatabaseConnection("mydb")
# conn3 = DatabaseConnection("anotherdb")
# print(conn1 is conn2) # True
# print(conn1 is conn3) # False
Python example demonstrating a factory-like pattern using __new__
to control instance creation, similar to a private constructor's role.