Composition Over Inheritance
By the end of this lesson, you'll be able to:
- Define composition: building a class out of other objects rather than extending a parent
- Recognize when a "has-a" relationship is a better fit than "is-a"
- Refactor an awkward inheritance hierarchy into composition
Prerequisites: "Polymorphism"
When inheritance stops fitting
// Awkward: does a DeliveryVan really "extend" an Engine?
public class Engine {
public void start() { System.debug('Engine running.'); }
}
public class DeliveryVan extends Engine { // this reads wrong
public Decimal cargoCapacityKg;
}
A DeliveryVan has an engine — it isn't a kind of engine. Forcing this into extends fails the "is-a" test from the Inheritance lesson, even though it compiles.
Composition: has-a instead of is-a
public class Engine {
public void start() {
System.debug('Engine running.');
}
}
public class DeliveryVan {
private Engine engine = new Engine();
public Decimal cargoCapacityKg;
public void startVehicle() {
engine.start();
}
}
DeliveryVan now holds an Engine as a field rather than extending it — a has-a relationship. startVehicle() delegates to the engine's own start() method rather than inheriting it directly. This reads correctly and stays flexible: swapping in an ElectricEngine later only means changing one field's type.
A real business example: Fitness (Gym Equipment Bundles)
public class HeartRateMonitor {
public Integer getCurrentBpm() {
return 72; // placeholder for real sensor data
}
}
public class Treadmill {
private HeartRateMonitor monitor = new HeartRateMonitor();
public String getWorkoutSummary() {
return 'Current heart rate: ' + monitor.getCurrentBpm() + ' bpm';
}
}
A Treadmill has a heart rate monitor built in — it definitely isn't a kind of heart rate monitor. Composition lets Treadmill reuse HeartRateMonitor's behavior without pretending they share a lineage they don't.
A rule of thumb
When deciding between extends and holding a field: say the relationship out loud. "A DeliveryVan is an Engine" sounds wrong; "a DeliveryVan has an Engine" sounds right. When "has-a" fits better than "is-a," reach for composition instead of inheritance — even though Apex would happily compile either one.
Exercise
Refactor this awkward inheritance (a Car extending a Radio) into composition: Car should hold a Radio as a field instead.
Show hint
private Radio radio = new Radio(); then delegate to it from a Car method.
Composition Over Inheritance Quiz
My Notes
Log in to keep private notes on this lesson.
Questions about this lesson
No questions yet — be the first to ask.
Log in to ask a question about this lesson.
Summary
Composition builds a class by holding references to other objects ("has-a") instead of extending a parent class ("is-a") — often a more flexible fit when the relationship isn't a clean lineage.