Composition over Inheritance
Composition over Inheritance is a principle in object-oriented programming (OOP) that suggests that classes should achieve code reuse and polymorphic behavior by containing instances of other classes that implement the desired functionality, rather than inheriting from a base or parent class.
1. The Core Concept
- Inheritance ("Is-A"): You design your types around what they are. (e.g., A
Caris aVehicle). - Composition ("Has-A"): You design your types around what they do or have. (e.g., A
Carhas anEngine).
The principle argues that Composition is generally more flexible and less brittle than Inheritance.
2. The Problems with Inheritance
While inheritance is powerful, overuse leads to several issues:
The Fragile Base Class Problem
Changes to the parent class can inadvertently break child classes. The child class is tightly coupled to the implementation details of the parent.
The Gorilla / Banana Problem
"You wanted a banana but what you got was a gorilla holding the banana and the entire jungle." β Joe Armstrong
When you inherit from a class, you get everythingβall its data and methods, even the ones you don't need.
Hierarchy Explosion
Imagine a game with Monster. You have FlyingMonster and SwimmingMonster. What happens when you need a FlyingSwimmingMonster? You can't inherit from both (in many languages). You end up with a deep, messy tree.
3. The Solution: Composition
Instead of inheriting behavior, you compose it. You create small, focused classes (components) and combine them.
Example: Inheritance (The Wrong Way)
class Robot {
void move() { ... }
void clean() { ... }
}
class CleaningRobot extends Robot {
// Inherits move and clean
}
class FightingRobot extends Robot {
// Inherits move and clean... but wait, fighting robots don't clean!
// Now you have a useless clean() method.
}
Example: Composition (The Right Way)
interface MovementBehavior {
void move();
}
interface CleaningBehavior {
void clean();
}
class Robot {
private MovementBehavior mover;
private CleaningBehavior cleaner;
public Robot(MovementBehavior mover, CleaningBehavior cleaner) {
this.mover = mover;
this.cleaner = cleaner;
}
void performTasks() {
if (mover != null) mover.move();
if (cleaner != null) cleaner.clean();
}
}
// Usage
Robot cleanerBot = new Robot(new Wheels(), new Vacuum());
Robot fighterBot = new Robot(new Legs(), null); // No cleaning behavior!
4. Benefits of Composition
- Flexibility: You can change behavior at runtime by swapping components (e.g., changing a
EnginefromGastoElectric). - Loose Coupling: Classes depend on interfaces, not concrete implementations.
- Testability: Easier to mock individual components.
- Single Responsibility: Each component does one thing well.
5. When to use Inheritance?
Inheritance isn't dead. Use it when:
- There is a strict "Is-A" relationship.
- You want to enforce a common interface (polymorphism) without code reuse (Interfaces/Abstract Classes).
- The base class code is stable and unlikely to change.
6. Mixins
Mixins are a form of code reuse that sits somewhere between inheritance and composition. A Mixin is a class containing methods that can be used by other classes without needing to be the parent class of those other classes.
- Concept: "Included" behavior. A class can "mix in" functionality from multiple sources.
- Language Support: Supported natively in languages like Ruby, Python (via multiple inheritance), and TypeScript/JavaScript.
Example (TypeScript)
// A Mixin that adds flying capability
function Flyable<TBase extends new (...args: any[]) => {}>(Base: TBase) {
return class extends Base {
fly() {
console.log("Flying high!");
}
};
}
// A Mixin that adds swimming capability
function Swimmable<TBase extends new (...args: any[]) => {}>(Base: TBase) {
return class extends Base {
swim() {
console.log("Swimming deep!");
}
};
}
class Monster {}
// Compose a new class using Mixins
const FlyingSwimmingMonster = Swimmable(Flyable(Monster));
const monster = new FlyingSwimmingMonster();
monster.fly();
monster.swim();
programming/object-oriented-programming programming/design-patterns programming/software-design-principles