All 15 Design Patterns in Java questions
More in Design Patterns in Java
Advertisement
Back to results for “Design Patterns in Java”
Java › Design Patterns in Java

What is the difference between composition and inheritance as ways to reuse code, and why does the design principle "favor composition over inheritance" generally guide modern Java design (including many design patterns themselves)?

Intermediate

Answer

Inheritance creates a tight, static "is-a" coupling between a subclass and its superclass (fixed at compile time, exposing all of a superclass's protected/public members and behavior, including behavior the subclass might not want, a problem known as the fragile base class problem where superclass changes can unexpectedly break subclasses); composition instead builds behavior by holding references to other objects (a "has-a" relationship) and delegating to them, which can be reconfigured at runtime, exposes only the specific behavior you choose to delegate, and avoids fragile base class issues entirely -- many design patterns (Strategy, Decorator, Composite) exist specifically as composition-based alternatives to what inheritance-based designs would otherwise attempt, which is why "favor composition over inheritance" is such a widely cited principle in object-oriented design.
// Inheritance-based (rigid, exposes ALL of Vehicle's behavior, fixed at compile time)
class Car extends Vehicle { }

// Composition-based (flexible, exposes only what Car chooses to delegate, reconfigurable at runtime)
class Car {
    private final Engine engine;  // composition: Car "has-a" Engine
    public Car(Engine engine) { this.engine = engine; }
    public void start() { engine.start(); }  // delegates, exposing only what Car chooses to
}
Real-world example A vehicle simulation initially modeled with deep inheritance hierarchies (ElectricCar extends Car extends Vehicle) is refactored to use composition instead (Car holds an Engine interface reference), letting the same Car class be reconfigured with different engine implementations at runtime and avoiding the fragile base class problems the original rigid inheritance hierarchy had caused as requirements evolved.

Common follow-ups: What specific problems does the 'fragile base class' issue cause in practice as a codebase evolves over time?;In what scenarios is inheritance still the genuinely correct and appropriate choice over composition?