Low-level designCore6 min
Coupling and cohesion
Cohesion is how well the parts inside a class belong together; coupling is how much a class depends on others, and on what. Aim for classes whose insides belong together and whose dependencies are few and shallow, and a change stays in one place.
An event, and a checkout
Event holds the venue, the attendees and the sponsors; Checkout quotes a price.
1 · The situation
An event, and everything about it
A community events app sells seats to meetups. An Event has a title, a venue, a list of attendees and its sponsors; a Checkout quotes a price, charging more for the last two seats. The first version puts everything about an event into one class, and the checkout works out the free seats itself:
class Event {
private final String title;
private final String venueName;
private final String venueAddress;
private final int capacity;
private final List<String> attendees = new ArrayList<>();
private final List<String> sponsors = new ArrayList<>();
Event(String title, String venueName, String venueAddress, int capacity) {
this.title = title;
this.venueName = venueName;
this.venueAddress = venueAddress;
this.capacity = capacity;
}
String title() {
return title;
}
String venueName() {
return venueName;
}
int capacity() {
return capacity;
}
List<String> attendees() {
return List.copyOf(attendees);
}
void register(String name) {
attendees.add(name);
}
void addSponsor(String sponsor) {
sponsors.add(sponsor);
}
String mapLink() {
return "maps.example/?q=" + venueAddress.replace(' ', '+');
}
String sponsorBanner() {
return "With thanks to " + String.join(", ", sponsors);
}
}
class Checkout {
// The last two seats cost more.
String quote(Event e) {
int left = e.capacity() - e.attendees().size();
if (left <= 0) return e.title() + ": sold out";
int dollars = left <= 2 ? 30 : 20;
return e.title() + " at " + e.venueName() + ": seats left " + left + ", $" + dollars;
}
}Drawn from the code: one large Event, and a Checkout that depends on it.
Open Source Night at Harbor Hall: seats left 3, $20 Open Source Night at Harbor Hall: seats left 1, $30 Map: maps.example/?q=12+Harbor+Road With thanks to Acme, Globex
2 · Low cohesion
Three things in one class
List which fields each of Event's methods uses, and the class falls apart into groups that never touch:
Methods | Fields they use | What they're about |
|---|---|---|
|
| The venue |
|
| Who's coming |
|
| Who's paying for it |
|
| The event itself |
That's low cohesion: the parts of the class don't depend on each other. It has practical costs. The venue's details are copied into every event held there, so a changed address means editing every event. And anyone reading Event must wade through sponsorship to find seating.
3 · Tight coupling
A checkout that knows how seats are counted
Checkout.quote() computes the free seats itself: capacity minus the length of the attendee list. So it depends not just on Event but on how Event stores attendance. The day canceled registrations are kept in the list for refunds, or the hall adds standing room, the checkout quotes the wrong number of seats, though nobody edited it.
That's tight coupling: one class depends on another's details, so changes inside one ripple into the other. The practice checks notice the symptom: Checkout.quote mostly works on Event.
4 · The fix
Group what belongs together, depend on less
Venue keeps its name, address and capacity, and makes its own map link. One venue can now be shared by every event held there.
class Venue {
private final String name;
private final String address;
private final int capacity;
Venue(String name, String address, int capacity) {
this.name = name;
this.address = address;
this.capacity = capacity;
}
String name() {
return name;
}
int capacity() {
return capacity;
}
String mapLink() {
return "maps.example/?q=" + address.replace(' ', '+');
}
}Open Source Night at Harbor Hall: seats left 3, $20 Open Source Night at Harbor Hall: seats left 1, $30 Map: maps.example/?q=12+Harbor+Road With thanks to Acme, Globex
The same quotes, map link and banner.
5 · What they are
Two measures of the same design
Cohesion is how strongly the parts inside a module belong together. Coupling is how much modules depend on each other. They often move together: pulling the venue out of Event raised Event's cohesion, and giving it seatsLeft() lowered the checkout's coupling, because the checkout now relies on one answer instead of two internals.
After the fix: three small classes, each about one thing, and a Checkout that depends on Event alone.
How one class depends on another | Example | Tightness |
|---|---|---|
Uses its internal details |
| Tightest |
Shares global data with it | Both read a global seat count | Tight |
Tells it how to work | A flag that picks which branch it runs | Medium |
Passes it a whole object it barely uses | Passing an | Loose |
Passes it just the data it needs |
| Loosest |
6 · Spotting them
Signals, not targets
Both can be estimated by reading code:
- Cohesion: do a class's methods use the same fields? Methods that share no fields with each other, like the venue, attendance and sponsor groups above, are separate jobs. Tools count such method pairs (the LCOM family of metrics).
- Coupling: how many other classes does a class use, and how many of their members? A class using four of another's getters to compute something is coupled to its internals.
After the fix: the checkout talks only to the event, and only the event knows about the venue.
Treat the numbers as signals, not goals. Zero coupling means classes that don't work together at all, and one-method classes have perfect cohesion and no use. The aim is coupling that's deliberate and narrow, and classes whose parts change together.
7 · In practice
What the checks look for
Several practice checks are coupling and cohesion in disguise: a class with many methods and many collaborators (a god class), a method that mostly uses another class's data (feature envy), and classes that depend on each other in a loop. The principle pages that follow, starting with Single responsibility principle, each sharpen one part of this idea.
Design the parking lot and keep its classes focused.
Check yourself
4 questions
Takeaways
Remember this
- Cohesion: how well the parts inside a class belong together.
- Coupling: how much a class depends on others, and how deeply.
- Methods that share no fields are a sign of low cohesion: separate jobs in one class.
- Depending on another class's internals is the tightest coupling; ask it for an answer instead.
- Aim for high cohesion and loose coupling; treat metrics as signals, not targets.