Class Diagrams

Boxes, lines, multiplicities. Association vs aggregation vs composition vs inheritance — what each arrow actually claims.

Concept Foundational
10 min read
uml class-diagram relationships multiplicity lld

Summary#

A class diagram is the structure picture: the nouns of your system and the relationships between them. It is the artefact the interviewer spends the most time reading because it is the artefact most directly tied to the code you would write afterward. A clean class diagram does three things at once: it names the entities, it states how many of each connect to how many of which, and it distinguishes the kind of connection (does one own the other? merely reference it? specialise it?).

The notation reduces to a small alphabet:

  • Class — a rectangle in three compartments: name on top, attributes (fields) in the middle, operations (method signatures) on the bottom. Visibility prefixes — `+` public, `-` private, `#` protected, `~` package — appear before each attribute or operation name.
  • Stereotypes`<<interface>>`, `<<abstract>>`, `<<enumeration>>` above the class name to tag the kind of box. Italicised names mean abstract.
  • Relationships — five kinds of line that mean five very different things: association, aggregation, composition, generalization (inheritance), realization (interface implementation).
  • Multiplicities — numbers or ranges at the line ends: `1`, `0..1`, `*`, `0..*`, `1..*`, `2..5`. They state how many instances on this end participate with how many on the other.

The diagram is read aloud as a series of small claims: “A ParkingLot is composed of one-or-more Floors. A Floor is composed of one-or-more ParkingSpots. A Ticket is associated with exactly one Vehicle and exactly one ParkingSpot.” If the diagram reads cleanly as those claims, it is doing its job.

Why it matters#

Most LLD interview points hinge on this diagram. The interviewer is checking four things at once.

Did you find the right nouns? Too few classes is under-modelling: a god ParkingLotManager doing everything. Too many is over-modelling: a TicketIssuer, a TicketValidator, a TicketReleaser where one Ticket with the right state machine suffices. A right-sized class diagram for a 45-minute problem usually has 6–12 boxes.

Did you pick the right relationships? Association versus aggregation versus composition is not stylistic — each makes a different claim about lifecycle and ownership. A Floor composed of ParkingSpots means the spots cannot outlive the floor; a Course aggregating Students means the students continue to exist when the course is deleted. Getting this wrong is the most common diagramming error and the easiest one for the interviewer to spot.

Did you respect SRP? If a class has eight methods and they fall into two clusters that do not share state, SRP says split. If Vehicle has parkingFee(), displayName(), serialize(), and validatePlate(), the diagram itself is whispering that fare logic, presentation, persistence, and validation each want their own home.

Did you avoid inheriting where you should have composed? A class diagram that uses generalization for every variant — MotorcycleSpot extends ParkingSpot, CompactSpot extends ParkingSpot, LargeSpot extends ParkingSpot — is usually telling you a SpotType field would have served better. The diagram makes the error visible because the inheritance triangles cluster on the page.

How it works#

A canonical mini class diagram, kept small enough to render in ASCII:

+----------------------+
| ParkingLot |
+----------------------+
| - floors : List<Floor> |
| - rates : RateTable |
| - payment : PaymentStrategy |
+----------------------+
| + parkVehicle(v) |
| + retrieveVehicle(t) |
+----------+-----------+
|
| composition 1
| <>---------------+
| 1..*
v
+----------------------+
| Floor |
+----------------------+
| - id : int |
| - spots : List<ParkingSpot> |
+----------------------+
| + findFreeSpot(v) |
+----------+-----------+
|
| composition 1
| <>---------------+
| 1..*
v
+----------------------+ <<interface>>
| ParkingSpot | +----------------------+
+----------------------+ | PaymentStrategy |
| - id : String | +----------------------+
| - type : SpotType | | + pay(amount) |
+----------------------+ +----------+-----------+
| + fits(v) : boolean | |
| + assign(t) | | realization
| + release() | +----------+-----------+
+----------------------+ | |
v v
+-------------+ +-------------+
| CashPayment | | CardPayment |
+-------------+ +-------------+

The relationships in this single diagram exhibit four of the five line types, which is roughly the ratio you should aim for in an interview: composition heavy, association where the lifecycle is independent, generalization or realization for true polymorphism.

The five relationship kinds#

Telling them apart is the load-bearing skill of class diagramming. Listed strongest-coupling to weakest:

Generalization — a solid line ending in a hollow triangle pointing at the parent class. “Subclass IS-A parent.” Used for true polymorphic specialisation. The Liskov question — can the subclass be substituted anywhere the parent is expected? — is the test for whether this line is correct.

Realization — a dashed line ending in a hollow triangle pointing at the interface (`<<interface>>` stereotype). “Concrete class implements interface.” The same triangle as generalization, but dashed.

Composition — a solid line with a filled diamond at the whole end. “Part-of, exclusively, with shared lifetime.” If the whole is deleted, the parts are deleted with it. A Floor composes ParkingSpots: no floor, no spots. A House composes Rooms: no house, no rooms.

Aggregation — a solid line with a hollow diamond at the whole end. “Part-of, but lifetimes are independent.” A Department aggregates Employees: deleting the department does not delete the employees. A Course aggregates Students: ending the course does not end the students. Aggregation is the relationship most candidates over-use; if in doubt, prefer plain association.

Association — a plain solid line between two classes. “These two classes know about each other; one references the other.” Usually given a name on the line (worksAt, assignedTo) and a multiplicity at each end.

Composition (filled diamond). “Cannot exist without me.” The lot owns its floors; deleting the lot deletes the floors. Use when the part has no meaning outside the whole.

Aggregation (hollow diamond). “Belongs to me, but survives me.” The department has employees, but the employees outlive any one department. Use sparingly — most “has-a” relationships are really plain association or composition.

Multiplicities#

The numbers at the line ends are how the diagram answers “how many?” Common values:

  • `1` — exactly one.
  • `0..1` — optional, at most one.
  • `*` or `0..*` — any number, including zero.
  • `1..*` — at least one.
  • `2..5` — between two and five inclusive.

Read in pairs at the two ends of a line. A ParkingLot `1` --- `1..*` Floor reads “each parking lot has one or more floors; each floor belongs to exactly one parking lot.” Multiplicities are not optional decoration — a class diagram without them is incomplete, and the interviewer will ask.

Visibility and stereotypes#

Inside the class box, attributes and operations get a visibility prefix. The defaults that match Java behaviour:

  • `- field` — private (default for fields).
  • `+ method()` — public (default for the public API).
  • `#` and `~` — protected and package-private; less common in interview diagrams.

Stereotypes go above the class name in guillemets: `<<interface>>`, `<<abstract>>`, `<<enumeration>>`. An abstract class can also be signalled by italicising the class name; an interview-friendly shortcut is to write `<<abstract>>` explicitly. For utility classes carrying only static methods, `<<utility>>` is the stereotype but rarely worth the ink.

A minimal Java sketch matching the diagram#

public interface PaymentStrategy {
Receipt pay(Money amount);
}
public final class CashPayment implements PaymentStrategy { /* ... */ }
public final class CardPayment implements PaymentStrategy { /* ... */ }
public final class ParkingSpot {
private final String id;
private final SpotType type;
public boolean fits(Vehicle v) { /* ... */ return true; }
public void assign(Ticket t) { /* ... */ }
public void release() { /* ... */ }
}
public final class Floor {
private final int id;
private final List<ParkingSpot> spots; // composition: floor owns its spots
public Optional<ParkingSpot> findFreeSpot(Vehicle v) { /* ... */ return Optional.empty(); }
}
public final class ParkingLot {
private final List<Floor> floors; // composition
private final RateTable rates; // association
private final PaymentStrategy payment; // association via interface
public Ticket parkVehicle(Vehicle v) { /* ... */ return null; }
public Receipt retrieveVehicle(Ticket t) { /* ... */ return null; }
}

Notice how each relationship in the diagram becomes a field declaration in Java. Composition shows up as a final field initialised in the constructor and never replaced; association shows up as a field whose target may have its own lifecycle managed elsewhere.

Variants and trade-offs#

A few recurring questions when drawing the diagram in an interview.

How much detail in each box? Always include the class name. Include fields when they matter for the relationships (a field of type Floor confirms the line to Floor). Include method signatures, not bodies — bodies belong in the Java implementation later. Three to seven methods per class is the comfortable range; ten-plus is a signal SRP wants to split.

Show getters and setters? Almost always no. They clutter the diagram without adding information. Note getId() only if its return type matters for another relationship in the diagram.

Enums and value objects? Draw them as classes with the `<<enumeration>>` stereotype, or sometimes as small unlabeled boxes in the corner. Whether SpotType deserves its own box depends on whether it has interesting structure (just three constants, probably skip; a class with state and methods, definitely draw).

Interface arrows: hollow triangle dashed or solid? Dashed for realization (a class implements an interface). Solid for generalization (a class extends a class, or an interface extends an interface). Mixing them up is a common error; the dash is the cue that this is the interface relationship.

When this is asked in interviews#

The class diagram is the artefact that takes the most board time and earns the most points. Three patterns interviewers reward.

Lead with the relationships, not the boxes. Most candidates draw all the boxes first, then add lines. The stronger move is to draw boxes one at a time and immediately commit to how they connect to the existing boxes. “I have ParkingLot. Now I add Floor — composition, multiplicity `1..*`. Now ParkingSpot — composition off Floor, multiplicity `1..*`.” The diagram grows with its relationships intact at every step, which mirrors how you should think about the model.

Resist god classes by counting methods. When a single box hits eight to ten methods, pause and audit. Each method should plausibly use the same set of fields. If two methods share no field accesses with the others, they want a separate class. The interviewer is watching for SRP, and the diagram makes the violation visible.

Use inheritance sparingly and defend each use. The strongest signal you can send: every generalization triangle on the board has a one-sentence justification involving the Liskov question. “Car, Motorcycle, and Truck all substitute for Vehicle in the parkVehicle call, because the only thing the lot does with a vehicle is read its type and plate.” If you cannot say that for a triangle on your board, replace the triangle with composition.

Common follow-up questions the diagram should make easy: “What happens if a Floor is removed?” (Composition: spots are removed too.) “Can a Vehicle be reused across tickets?” (Plain association: yes, the vehicle outlives a single ticket.) “Can PaymentStrategy have stateful implementations?” (Yes — the interface is the contract, state is the implementation’s business.)

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.