Free lesson · Low Level Design Fundamentals
Class Diagram
Class Diagram
A class diagram is the structural backbone of UML: it shows the classes in a system, the attributes and operations each one has, and - most importantly - the relationships between them. The intent is to capture, in a single picture, what the system is made of and how the parts connect, at a level of detail that maps almost directly to code. Of all UML diagrams, the class diagram is the one you'll draw most often in an LLD interview, because nearly every "design X" question is, at its core, a request for a class structure.
This is the first and most fundamental diagram type, building directly on Classes and Objects (Module 2) and on the composition-versus-inheritance distinction (Module 5) - the class diagram is precisely where those relationship choices become visible. It's also the canonical notation for design patterns: every pattern in Modules 14–21 is conventionally communicated as a small class diagram, so fluency here is a prerequisite for discussing patterns at all.
In interviews, the discriminating skill is not drawing boxes - anyone can do that - but using the correct relationship notation, because the difference between inheritance, composition, aggregation, and a plain dependency is exactly the difference between several quite different designs. Getting the arrows right signals that you understand object relationships, not just object lists.
The Problem It Solves
A list of classes tells you almost nothing; the relationships are the design:
Classes: Order, OrderLine, Customer, Product, PaymentGateway, StripeGateway
Does an Order own its OrderLines (so they die with it) or merely reference them? Is StripeGateway a kind of PaymentGateway or does it use one? Does Order hold a Customer or just a customer id? The class names are silent on all of this - yet these are the decisions that determine lifecycle, coupling, and substitutability. A class diagram makes every one of them explicit and visible at a glance.
The Notation That Matters
A class is a box with three compartments - name, attributes, operations - and visibility markers (+ public, - private, # protected). The relationships are where precision counts:
classDiagram
class PaymentGateway {
<<interface>>
+charge(Money) PaymentResult
}
class StripeGateway {
-apiKey: String
+charge(Money) PaymentResult
}
class Order {
-id: OrderId
-status: OrderStatus
+addLine(OrderLine)
+total() Money
}
class OrderLine {
-quantity: int
-unitPrice: Money
}
class Customer {
-id: CustomerId
-name: String
}
PaymentGateway <|.. StripeGateway : implements
Order "1" *-- "many" OrderLine : composition
Order "many" o-- "1" Customer : aggregation
Order ..> PaymentGateway : depends on
A class diagram for an ordering system. PaymentGateway is an interface with a charge operation, and StripeGateway implements it, shown by a dashed line with a hollow triangle arrowhead pointing to the interface. Order has a composition relationship to OrderLine, drawn with a filled diamond at the Order end, with multiplicity one Order to many OrderLines, meaning the lines are owned by the order and do not exist without it. Order has an aggregation relationship to Customer, drawn with a hollow diamond, meaning many orders reference one customer who exists independently. And Order has a dependency on PaymentGateway, drawn as a dashed arrow, meaning it uses the gateway without owning it. Each arrow style encodes a distinct kind of relationship.
The relationship vocabulary, from strongest to weakest coupling:
- Inheritance / realization (hollow triangle, solid for
extends, dashed forimplements): an is-a relationship.StripeGatewayis aPaymentGateway. - Composition (filled diamond): a strong owns-a where the part's lifecycle is bound to the whole.
OrderLines belong to oneOrderand die with it. - Aggregation (hollow diamond): a weaker has-a where the part lives independently. A
Customerreferenced by manyOrders outlives any one of them. - Association (plain line, often with multiplicity): a general structural link between objects.
- Dependency (dashed arrow): the weakest - one class uses another transiently, e.g. as a method parameter.
Multiplicity (1, many/*, 0..1, 1..*) on the ends quantifies the relationship and is one of the most information-dense things you can add.
How Much Detail to Show
A class diagram can range from a quick whiteboard sketch (boxes + key relationships) to a fully-typed specification. For interviews and design discussion, favor the lighter end: show the classes that matter, the relationships between them with correct arrows, and only the few attributes/operations that are essential to the point. Omit getters, setters, and obvious fields - they add noise without adding design information. The composition-vs-aggregation and inheritance-vs-dependency distinctions, by contrast, are never noise: they're the design.
Why This Matters in Interviews
The class diagram is the primary deliverable of most LLD interviews, so drawing one quickly and correctly is close to mandatory. The depth signal is relationship precision: choosing composition over aggregation (or vice versa) and being able to justify it - "an OrderLine has no meaning without its Order, so it's composition" - shows you reason about ownership and lifecycle. Using the inheritance arrow only for genuine is-a relationships, and a dependency arrow for uses-a, demonstrates you won't model a has-a as an is-a (the classic mistake LSP, Module 10, warns against).
Common Mistakes
- One arrow for all relationships. Drawing every link as a plain line loses the composition/aggregation/inheritance/dependency distinctions that are the design.
- Inheritance for has-a. Using the is-a arrow where composition is meant - the modeling root of many LSP violations.
- Composition vs aggregation confusion. Filled vs hollow diamond matters: it's the difference between owned-and-bound and referenced-and-independent.
- Attribute clutter. Listing every getter/setter and trivial field, burying the relationships that matter.
- Missing multiplicity. Omitting the
1/manyannotations that quantify relationships and often reveal design decisions.
Try It
Take a domain you know and draw its class diagram, forcing yourself to choose the correct arrow for every relationship - and to justify each composition vs aggregation choice out loud ("does the part survive without the whole?"). Then add multiplicity to every relationship. Finally, pick one design pattern from Modules 14–21 and draw its class diagram from memory; if you can render a pattern in correct UML, you can both recognize it in a diagram and communicate it in an interview.