OOP FundamentalsPolymorphismHard⏱️ ~3 min

Polymorphism Trade-Offs: When to Use vs Alternatives

When Polymorphism is Appropriate

First, when you have a family of related types that share common behavior but differ in implementation details. Second, when you need to add new types frequently without modifying existing code (OCP). Third, when behavior varies by type, not by state or configuration. Fourth, when client code should depend on abstractions, not concrete implementations (DIP).

When Polymorphism is Overkill

Scenario 1: Simple Conditional Logic. If you only have two states and behavior rarely changes, a simple if-else is clearer than creating a class hierarchy. For example, handling isActive flag does not need polymorphism; use a boolean check instead.

Scenario 2: Behavior Varies by Configuration. If the variation is data-driven (rates, thresholds, rules stored in a database), use Strategy Pattern with configuration, not inheritance. Polymorphism through inheritance is static; you cannot change an object's class at runtime, but you can swap strategies.

Scenario 3: Cross-Cutting Concerns. If you need to add behavior across multiple unrelated classes (logging, authentication), polymorphism through inheritance creates awkward hierarchies. Use Decorator Pattern or Aspect-Oriented Programming instead.

Polymorphism vs Alternatives

Polymorphism (Inheritance)
Use when: Types are inherently related and form an "is-a" hierarchy. Behavior varies by type essence.

Example: Vehicle hierarchy (Car is-a Vehicle)
Strategy Pattern (Composition)
Use when: Behavior varies independently of type and can change at runtime. Prefer composition over inheritance.

Example: Payment methods (behavior, not type)
Conditional Logic (if-else/switch)
Use when: Only 2-3 simple cases that rarely change. Creating classes adds unnecessary complexity.

Example: Handling AM/PM in time display
Visitor Pattern
Use when: You need to add operations to a stable class hierarchy without modifying classes.

Example: Different export formats for library items

Common Pitfall: Deep Inheritance Hierarchies

Polymorphism through inheritance can lead to rigid, deep hierarchies that are hard to modify. If you find yourself with more than 3-4 levels of inheritance, consider flattening the hierarchy using composition and interfaces instead. For example, if ElectricCar extends Car extends Vehicle, and you need to add ElectricMotorcycle, the hierarchy becomes awkward. Instead, use a PowerSource interface with ElectricPowerSource and GasolinePowerSource implementations composed into vehicles.

Interview Tip: When asked "Why use polymorphism here?", articulate the specific extensibility benefit. Avoid generic answers like "it's flexible." Instead, say "Adding a new vehicle type requires no changes to the ParkingLot class, which satisfies OCP."
💡 Key Takeaways
Use polymorphism when types form a natural is-a hierarchy and behavior varies by type essence
Avoid polymorphism for simple conditionals, data-driven behavior, or cross-cutting concerns
Composition with Strategy Pattern is more flexible than inheritance when behavior changes at runtime
Deep inheritance hierarchies (more than 3-4 levels) become rigid; prefer composition and interfaces
Articulate specific extensibility benefits, not generic flexibility claims
📌 Examples
1Good: Payment processing where each method is fundamentally different (CreditCard, BankTransfer)
2Bad: Discount calculation where rates come from database (use Strategy with configuration instead)
3Bad: Adding logging to all classes (use Decorator or AOP, not inheritance)
← Back to Polymorphism Overview
Polymorphism Trade-Offs: When to Use vs Alternatives | Polymorphism - System Overflow