Unit 12 · lesson
Prefer the Relationship You Can Defend
Composition and inheritance can sometimes solve the same immediate coding problem. Their long-term claims are different.
Inheritance:
A is a B
A inherits/overrides B behavior
A must remain substitutable for B's contract
Composition:
A has a B/capability
A delegates some responsibility
collaborator can often be replaced independently
Example: powered device
Bad instinct:
Robot extends Battery
A robot uses a battery. It is not a battery.
Composition expresses the domain:
class Robot {
private final PowerSource power;
}
Example: notification specialization
If UrgentNotification genuinely preserves every Notification expectation and only specializes formatting/priority behavior, inheritance may be reasonable.
But if urgent notices have an entirely different lifecycle and incompatible operations, a separate implementation of a Notification interface may be cleaner than subclassing a concrete parent.
Reuse is not enough evidence
Suppose two classes both need:
String sanitize(String text)
That does not prove one class should extend the other. Shared behavior can live in a focused collaborator or utility when no subtype relationship exists.
Do not create a dishonest hierarchy to save ten lines.
Change direction matters
Inheritance couples a subclass to details and contracts of its superclass. Changes in parent behavior can affect all descendants.
Composition couples a class to a collaborator contract. A new implementation can often be introduced without modifying the coordinator.
Neither is free. The design question is which dependency reflects the domain and expected change pattern.
Design review
Take this fictional system:
EmailAlert
ConsoleAlert
UrgentEmailAlert
AlertFormatter
DeliveryChannel
Create two possible architectures:
- an inheritance-heavy tree;
- an interface + composition design.
Evaluate each by:
- substitutability;
- responsibility clarity;
- change impact;
- testability;
- whether the is-a sentences remain true.
You may choose a hybrid if you can defend it.
Rejected inheritance evidence
A strong software designer can explain why they did not use inheritance.
Choose one pair of classes where shared code makes inheritance tempting but the domain relationship is weak.
Write:
Tempting hierarchy:
Why it compiles:
Why the is-a claim is weak/false:
Composition or other alternative:
Tradeoff accepted:
Evidence
Submit one inheritance decision and one composition decision from the same small system. The rubric rewards the reasoning, not the number of extends keywords.