The short version
- A class box has three parts: name, fields, methods. + is public, - is private, # is protected. Interfaces, abstract classes and enums are marked above the name.
- Six relationships cover almost everything, and each has a clear shape in code: extends, implements, a field you own, a field you share, a field you refer to, or a parameter you use briefly.
- Composition versus aggregation comes down to one question: if the whole disappears, does the part disappear with it?
- Multiplicity (1, 0..1, , 1..) on a line says how many objects are at each end.
- Class diagrams show structure; sequence diagrams show a flow over time. Interviews usually need one of each. Build both up in versions, from the requirements.
Before we start
A class diagram is a map of your design. Each box is a class, and each line says how two classes are connected. An interviewer reads it in seconds and immediately sees whether your design makes sense, long before any code exists.
UML (the Unified Modeling Language) defines many diagram types. For LLD interviews, two matter:
| Diagram | Shows | Draw it when |
|---|---|---|
| Class diagram | the classes, what they hold, and how they’re connected | always, after finding the entities |
| Sequence diagram | one flow, call by call, over time | to walk through the main use cases |
This chapter covers the class box, the six relationships (each with the Java it turns into), multiplicity, sequence diagrams, and a method for building a diagram from requirements. The LLD practice workspace has a whiteboard with exactly these boxes and arrows, so you can practise drawing them.
The class box
A class is a box with three sections: the name, the fields, and the methods.
The rules:
| Mark | Means | Java |
|---|---|---|
+ | public | public |
- | private | private |
# | protected | protected |
~ | package-private | no modifier |
name: Type | a field and its type | private Type name; |
method(arg: Type): Result | a method, its parameters and return type | Result method(Type arg) |
And the kinds of box, marked above the name:
Interfaces have methods but no fields. Abstract classes are written in italics in UML (our diagrams mark them «abstract»). Enums list their values.
How much to write: in an interview, only what matters to the design. The key fields, the methods other classes call, and the types that show relationships. Skip getters, setters, constructors and toString. A box with fifteen trivial methods hides the three that matter.
The six relationships
Every connection between two classes is one of six kinds. They differ in how strongly the two are tied together, from “is a kind of” down to “uses for a moment”. Each one turns into a specific shape in code, and knowing that mapping is what lets you draw a diagram from code or code from a diagram.
| Relationship | Line | Read it as | In code |
|---|---|---|---|
| Inheritance | solid line, hollow triangle | “is a” | class B extends A |
| Realization | dashed line, hollow triangle | “can do”, “implements” | class B implements A |
| Composition | solid line, filled diamond at the owner | “is made of; parts die with it” | a field the owner creates and never shares |
| Aggregation | solid line, hollow diamond at the owner | “has; parts live on their own” | a field holding things created elsewhere |
| Association | solid line, open arrow | “knows about” | a field referring to another object |
| Dependency | dashed line, open arrow | “uses for a moment” | a parameter, local variable or return type |
Here are all six, on one small design for a food delivery app:
The rest of this section takes each line in turn, with the code it means.
Inheritance: “is a”
A solid line with a hollow triangle pointing at the parent.
abstract class Account {
protected final String id;
Account(String id) { this.id = id; }
}
final class CustomerAccount extends Account { // the triangle
CustomerAccount(String id) { super(id); }
}Use it only for a genuine “is a” with shared behaviour; chapter 1 shows why. On a whiteboard, put parents above children so triangles point up.
Realization: “can do”
A dashed line with a hollow triangle pointing at the interface. It means the class implements the interface.
interface PaymentMethod {
boolean charge(long paise);
}
final class UpiPayment implements PaymentMethod { // the dashed triangle
public boolean charge(long paise) { return paise > 0; }
}Realization lines are where your design’s extension points are. An interviewer looking for “how would you add X?” looks here first.
Composition: “made of, and can’t exist without”
A filled diamond at the owner’s end. The parts are created by the owner, belong to only that owner, and have no meaning without it. Delete the order and its lines go with it.
final class Order {
private final List lines = new ArrayList<>(); 1
private final CustomerAccount customer; // see "Association"
Order(CustomerAccount customer) { this.customer = customer; }
void add(String dish, int qty) { lines.add(new OrderLine(dish, qty)); } // (2)
List lines() { return List.copyOf(lines); }
}
record OrderLine(String dish, int qty) { } - 1created inside
- The owner holds the parts privately.
- The owner creates them. Nobody else holds a reference to a line that could outlive the order.
Aggregation: “has, but they live separately”
A hollow diamond at the owner’s end. The owner holds a collection, but the parts were created elsewhere and can exist without it, or belong to several owners. A restaurant’s menu lists dishes, but a dish can be on several menus (dine-in and delivery), and still exists if one menu is deleted.
record Dish(String name) { }
final class Restaurant {
private final List menu = new ArrayList<>();
void addToMenu(Dish d) { menu.add(d); } // (1)
List menu() { return List.copyOf(menu); }
} - The dish comes from outside, and may be shared. That’s the difference from composition in code.
The lifetime test
Composition and aggregation look almost the same, and confuse everyone. One question settles it:
class LifetimeDemo {
public static void main(String[] args) {
Dish thali = new Dish("Veg thali");
Restaurant dineIn = new Restaurant(), delivery = new Restaurant();
dineIn.addToMenu(thali);
delivery.addToMenu(thali); // shared by two owners
dineIn = null; // close dine-in
System.out.println("delivery menu still has: " + delivery.menu());
Order o = new Order(new CustomerAccount("c1"));
o.add("Veg thali", 2);
System.out.println("order lines: " + o.lines());
}
}delivery menu still has: [Dish[name=Veg thali]]
order lines: [OrderLine[dish=Veg thali, qty=2]]The thali outlived the dine-in menu: aggregation. An order line on its own (“2 × veg thali”, for no order, for nobody) is meaningless: composition.
| Whole | Part | Part outlives whole? | Relationship |
|---|---|---|---|
| Parking floor | Parking spot | no | composition |
| Order | Order line | no | composition |
| Game | Board | no | composition |
| Team | Player | yes | aggregation |
| Restaurant | Dish on its menu | yes (shared) | aggregation |
| Parking lot | Active tickets | yes (the driver keeps it) | aggregation |
If you’re unsure in an interview, say which you chose and why. The reasoning earns more credit than the diamond.
Association: “knows about”
A solid line, usually with an open arrow showing which side knows about the other. One class keeps a reference to another for a long time, but doesn’t own it. The order above holds the customer who placed it: the customer exists before the order and long after it.
In code, it’s a field, like aggregation, but for a single related object rather than a collection the class “has”. The line can carry a label for the role (“placed by”) and multiplicity.
Dependency: “uses for a moment”
A dashed line with an open arrow. One class uses another briefly: as a parameter, a local variable or a return type, but doesn’t keep it.
final class InvoicePrinter {
String print(Order o) { // (1)
StringBuilder sb = new StringBuilder("INVOICE\n");
for (OrderLine l : o.lines())
sb.append(l.qty()).append(" x ").append(l.dish()).append('\n');
return sb.toString();
}
}- The printer needs an order only while printing. If it stored the order in a field, it would be an association instead.
Association or dependency? Ask: is it a field? A field is an association (or composition or aggregation). A parameter or local variable is a dependency.
Multiplicity: how many?
Numbers at the ends of a line say how many objects take part.
| Written | Means | Example |
|---|---|---|
1 | exactly one | a ticket has exactly one spot |
0..1 | none or one | a spot has at most one vehicle |
* or 0..* | any number, including none | a restaurant has any number of dishes |
1..* | at least one | an order has at least one line |
2..4 | a range | a game of ludo has two to four players |
Multiplicity carries real design information. “An order has 1..* lines” means an empty order is invalid, so something must stop one being created: that’s a check in the builder or constructor. “A spot has 0..1 vehicles” is the whole concurrency problem of the parking lot in three characters.
Sequence diagrams: one flow, over time
A class diagram shows structure: what exists and how it’s connected. It doesn’t show what happens. For that, draw a sequence diagram: the objects across the top, time going down, and each call as an arrow.
The rules:
| Element | Means |
|---|---|
| Box at the top | an object (or a role) taking part |
| Solid arrow | a call |
| Dashed arrow | a return value |
| Arrow to itself | a call to its own method |
Draw one for each main use case after the class diagram’s first version. Walking a flow call by call is where you discover missing methods and wrong owners while changing them is still just redrawing a box. Every problem walkthrough in this track has a step called “walk the flows” for exactly this reason, and it changes the design every time.
From requirements to diagram
Don’t draw the final diagram in one go. Build it in versions, out loud, so the interviewer can follow and correct you early. Here’s the method, applied to a small library system: members borrow books; each book can have several copies; a member can hold at most five loans; late returns pay a fine that may change.
Step 1Nouns become candidate classes
Library, member, book, copy, loan, fine, due date. Keep the ones with their own data and rules (the parking lot walks through this filter in detail). “Due date” is a field on a loan; “fine” is a rule that will change, so it becomes an interface.
Step 2The structure
A book is made of its copies (a copy of nothing is meaningless): composition. The library has books and members that it didn’t create in any meaningful sense: aggregation.
Step 3The things that happen
A loan connects a member and a copy, with dates. It’s an object in its own right, because it has its own data (due date) and rules (one active loan per copy).
Step 4What will change
The fine rule will change, so it goes behind an interface. That’s the realization line an interviewer looks for.
Step 5Check every requirement has a home
| Requirement | Where it lives |
|---|---|
| Members borrow books | Library.lend creates a Loan |
| Several copies per book | Book *-- BookCopy |
| At most five loans per member | checked in Library.lend, using active loans |
| Late returns pay a fine | FinePolicy, applied in Library.giveBack |
| Fine rules change | the interface, with two implementations |
That table is the last thing to show. If a requirement has no home, the design is incomplete; if a class serves no requirement, it shouldn’t be there.
Common mistakes
- Drawing everything at once, so the interviewer can’t follow and you can’t change direction cheaply.
- A class for every noun, including people and places the system never stores.
- Aggregation everywhere. When unsure, a plain association line is fine. Wrong diamonds are worse than no diamonds.
- Arrows pointing the wrong way. Inheritance and realization triangles point at the parent or interface; composition and aggregation diamonds sit at the owner.
- No multiplicity on the lines that matter, especially
0..1and1..*, which carry rules. - Getters and setters in every box, hiding the methods that matter.
- A class diagram with no sequence diagram, so nobody checks that the design actually supports the flows.
How this shows up in interviews
Most LLD rounds expect a class diagram within the first 15 to 20 minutes, built in versions and talked through. A good rhythm:
- Two minutes: boxes for the core entities, with the relationships that show structure.
- Five minutes: the key methods and the interfaces where change will come.
- Five minutes: a sequence diagram for the main flow, fixing the class diagram as the flow exposes gaps.
- Then code, starting from the smallest piece that must be correct.
Interviewer: Is the relationship between a parking floor and its spots composition or aggregation?
You: Composition. A spot has no meaning outside its floor: it’s created as part of the floor, it’s never moved to another floor, and if the floor is demolished the spots go with it. Compare the lot and its active tickets: a ticket is handed to the driver and outlives the lot’s list of active tickets, so that one is aggregation.
Stay in the loop
Get new problems and walkthroughs by email
One short email when something new is published: a deep-dive walkthrough, an LLD problem, or a real outage retold. No spam, unsubscribe any time.