Inheritance vs Composition: Two Core Relationship Patterns in Object-Oriented Design

Nov 23, 2025 · Programming · 11 views · 7.8

Keywords: Inheritance | Composition | Object-Oriented Design | Java Programming | Design Patterns

Abstract: This article provides an in-depth exploration of the fundamental differences between inheritance and composition in object-oriented programming. Inheritance establishes "is-a" relationships, representing class hierarchies, while composition builds "has-a" relationships through object references for functionality reuse. Using the design flaw of Java.util.Stack as a case study, the article demonstrates why composition is often preferable to inheritance, with complete code examples to help developers master proper object-oriented design principles.

Fundamental Concepts of Inheritance and Composition

In object-oriented programming, inheritance and composition represent two fundamentally different class relationship patterns. Inheritance embodies an "is-a" relationship, where a subclass is a specialized type of its parent class, while composition represents a "has-a" relationship, where one class contains an instance of another class as a component.

The Nature and Limitations of Inheritance

Inheritance is implemented using the extends keyword, establishing hierarchical relationships between classes. This relationship semantically indicates that the subclass is a specialized form of the parent class. However, excessive use of inheritance can lead to rigid designs, particularly when modifying base class behavior may break functionality in all derived classes.

Advantages and Implementation of Composition

Composition achieves functionality reuse by including instances of other classes as field members. This approach offers greater flexibility, as component objects can be dynamically replaced at runtime without affecting the interface of the class using them.

// Composition pattern example
class Engine {
    public void start() {
        System.out.println("Engine started");
    }
}

class Car {
    private Engine engine;  // Composition relationship: Car has an Engine
    
    public Car() {
        this.engine = new Engine();
    }
    
    public void startCar() {
        engine.start();
        System.out.println("Car is ready to drive");
    }
}

The Design Lesson from Stack Class

The design of java.util.Stack extending java.util.Vector is widely regarded as a classic mistake in object-oriented design. A stack is not a vector and should not allow arbitrary insertion and removal of elements. This inheritance relationship violates the LIFO (Last-In-First-Out) principle of stacks.

The correct design should use composition:

// Proper Stack implementation using composition
class ProperStack<E> {
    private List<E> elements;  // Composition instead of inheritance
    
    public ProperStack() {
        this.elements = new ArrayList<>();
    }
    
    public void push(E item) {
        elements.add(item);
    }
    
    public E pop() {
        if (elements.isEmpty()) {
            throw new EmptyStackException();
        }
        return elements.remove(elements.size() - 1);
    }
    
    public boolean isEmpty() {
        return elements.isEmpty();
    }
}

Design Principles and Practical Recommendations

According to Josh Bloch's advice in Effective Java:

Good object-oriented design should not involve freely extending existing classes. A developer's first instinct should be to consider composition, reserving inheritance only for genuine "is-a" relationships.

Conclusion

Both inheritance and composition have their appropriate use cases, but composition typically offers better design flexibility and maintainability. By understanding the fundamental differences between these two relationship types, developers can make more informed design decisions and build more robust and maintainable object-oriented systems.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.