The Relationship Nobody Names But Everyone Has
A ReportGenerator calls PDFExporter.export(data) inside one method. It doesn’t hold the exporter as a field, doesn’t own it, forgets it when the method returns. That fleeting link — uses-a — is a dependency: class A compiles against B but holds no lasting reference. It is the weakest bond in the relationship hierarchy, and managing how many of them exist is most of what “low coupling” means.
The Coupling Ladder
weakest ──────────────────────────────────────────────► strongest
┌────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Dependency │ < │ Association │ < │ Aggregation │ < │ Composition │
│ uses-a │ │ knows-a │ │ has-a │ │ part-of │
│ param/local│ │ field │ │ injected │ │ created │
│ │ │ │ │ externally │ │ internally │
└────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
lifetime of link: method call only → object lifetime → whole's lifetime
Left to right, both coupling strength and lifecycle entanglement grow. Dependencies are cheap to change (edit one signature), composition expensive (ownership semantics everywhere) — which is why designers prefer the left end whenever behavior permits.
Java Mechanics
class ReportGenerator {
// DEPENDENCY: exporter exists only for this call
Report render(Data d, PDFExporter exporter) {
return exporter.export(format(d));
}
}
// vs ASSOCIATION — longer-lived knowledge:
class ReportGenerator {
private final PDFExporter exporter; // field = association
ReportGenerator(PDFExporter e) { this.exporter = e; }
}
Same two classes; different structural commitment. The dependency version can mix exporters per call; the association version commits at construction.
Why Dependencies Are Preferred Where Possible
- Compile-time footprint:
ReportGeneratorneedsPDFExporteron its import list only — no shared lifecycle reasoning. - Testing: pass a stub exporter per test call; no wiring framework needed.
- Refactoring safety: fewer fields = fewer invariants about state consistency between objects.
When the Weakest Bond Is Too Weak
- Same collaborator needed by five methods with consistent configuration → promote to field (association/injection); parameter-passing repetition becomes its own smell.
- Stateless utilities (formatters, validators) are natural dependencies.
- Stateful or pooled resources (connections, transactions) must not be casual dependencies — their lifecycle demands explicit ownership.
UML Notation
Dashed arrow from user to used:
ReportGenerator ┄┄┄► PDFExporter («use» stereotype optional)
Dashed = transient; solid lines are reserved for durable structural links.
Interview Signals
- Distinguishing dependency from association correctly on diagrams (“this one’s a dashed arrow — it’s just a parameter”) is a common discriminator.
- Naming dependency injection as managed dependency — the container decides the association-vs-dependency trade-off per scope — connects this page to real frameworks.
Premium Content
Unlock Dependency and all premium lessons with a subscription.
From ₹199.99/year — See plans