Why should constructors on abstract classes be protected, not public?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When designing object-oriented software in languages such as Java or C#, a common practice is to create abstract classes to define a common template that can be shared by multiple subclasses. These abstract classes often contain a mixture of implemented methods and abstract methods (methods without an implementation that must be defined in a concrete subclass).
One critical aspect of abstract classes is their constructor visibility. There is a standard practice to define constructors in abstract classes as `protected` rather than `public`. But why is this the recommended approach? This article explores the reasons behind this convention, providing technical explanations and examples.
Understanding Abstract Classes
Before delving into why constructors should be protected, it is essential to understand what an abstract class is. An abstract class:
- Cannot be instantiated directly.
- Can have both implemented and abstract methods.
- Serves as a blueprint for its subclasses.
Consider the following example in Java:
- By definition, abstract classes cannot be instantiated directly. However, if a constructor is `public`, it might create confusion, misleading users into thinking instantiation is possible.
- A `protected` constructor communicates the intended usage more clearly: it is only to be called from subclasses.
- Using `protected` helps in maintaining a lower level of visibility, thus respecting the principles of encapsulation. Only classes within the same package or subclasses can access them, thus keeping more control over how and when the objects are constructed.
- A `protected` constructor explicitly defines that only subclasses are intended to call it. This adds clarity and reinforces the design intent, making the code easier to understand and maintain.
- Instructors of subclasses can rely on the `protected` constructor to perform initialization that should not be publicly accessible. It provides more flexibility to subclass implementations while maintaining a consistent base initialization logic.
- Defining a constructor as `protected` ensures that only relevant classes can extend the abstract class. This prevents unwanted subclasses from other packages unless intentionally designed to do so.

