Why Notation Precision Matters
A class diagram is a contract between designers and implementers. Sloppy notation (“just draw boxes with names”) loses exactly the information interviews and design reviews grade: who can call what, what is shared, what must be overridden. The class box has a fixed grammar; five minutes learning it makes every diagram readable for life.
Anatomy of a Class Box
┌─────────────────────────────────┐
│ BankAccount │ ← name; italics = abstract class;
│ «interface» PaymentProcessor │ «interface»/«abstract» stereotype optional
├─────────────────────────────────┤
│ - balance: long │ ← attributes section:
│ # id: UUID │ visibility name: Type [ = default]
│ + ownerName: String │ underlined text = static
│ {readOnly} createdAt: Instant │ {readOnly} = final-ish constraint
├─────────────────────────────────┤
│ + deposit(amount: Money): void │ ← operations section:
│ - withdraw(a: Money): void │ visibility name(params): ReturnType
│ # validate(a: Money): boolean │ italic signature = abstract method
│ + static of(x: long): Account │ underlined = static method
└─────────────────────────────────┘
The three compartments are conventional but only the name is mandatory in sketches; full form appears in formal reviews.
Visibility Markers
| Symbol | Meaning | Java |
|---|---|---|
+ | public | public |
- | private | private |
# | protected | protected |
~ | package | default (no modifier) |
Reading Rules That Carry Information
- Italicized class name → abstract; concrete subclasses expected below it.
- Underlined member → static (class-level, no instance needed).
- Abstract operation (italic) → no body in this class; every concrete subclass must implement.
- Default values (
balance: long = 0) → initialization behavior worth documenting. - Derived attributes marked
/:/area: inton Rectangle — computed, not stored.
A Fully Worked Mini-Diagram
┌──────────────«abstract»──────────────┐
│ Shape │
├───────────────────────────────────────┤
│ # origin: Point │
├───────────────────────────────────────┤
│ + area(): double «abstract» │
│ + move(dx, dy): void │
└────────────────△──────────────────────┘
│ extends
┌──────────┴──────────┐
┌──────┴──────┐ ┌──────┴──────┐
│ Circle │ │ Rect │
│ - r: double │ │ - w,h: int │
│ area():πr² │ │ area(): w·h │
└─────────────┘ └─────────────┘
Read aloud: Shape is abstract (cannot instantiate); declares abstract area() so both children must compute area their own way; move() inherited by both unchanged; protected origin visible to children.
Common Mistakes Interviewers Penalize
- Omitting visibility entirely (
deposit(...)instead of+deposit(...)) — hides encapsulation intent. - Drawing fields public that the code keeps private — diagram contradicts implementation.
- Marking nothing abstract while claiming “template pattern” verbally.
- Confusing underline (static) with italics (abstract) — opposite meanings.
The Problem
Six arrows exist because “A relates to B” is underspecified in exactly the ways that change code: lifetime ownership, navigation direction, and identity inheritance. Choosing the wrong arrow on a whiteboard communicates the wrong implementation contract — and interviewers grade arrow choice as modeling ability.
The Arrow Zoo
| Relationship | Symbol (A → B) | Phrase | Java form | Strength |
|---|---|---|---|---|
| Dependency | ┄┄┄► dashed | A uses B | B in a method signature | weakest |
| Association | ────► solid + role names | A knows B | B as field | |
| Aggregation | ◇─── hollow diamond at whole | A has B (B survives) | injected collection/field | |
| Composition | ◆─── filled diamond at whole | A owns B (B dies with A) | created internally | |
| Generalization | ───▷ solid triangle at parent | A is-a B | extends | strongest |
| Realization | ┄┄▷ dashed triangle at interface | A acts-as I | implements |
Diamonds sit on the whole; triangles point at the parent.
One Diagram, All Six
┌───────────┐
┄┄┄uses │ «interface»│
Order ┄┄┄┄┄┄┄┄► │ Pricable │◁┄┄┄ SeasonalPricing
(passes to └───────────┘ (realization)
calculator) △
│ implements
┌────────┐ 1 0..* ┌─────────────┐ ◆ 1..* ┌───────────┐
│Customer│─────────────►│ Order │────────│ OrderLine │
└────────┘ places └──────┬──────┘ owns └───────────┘
(association) │ aggregation? composition?
▼ decided by lifecycle:
lines die with order ⇒ COMPOSITION (filled)
Reading it aloud forces every decision into the open: orders use pricing transiently (dashed); customers know their orders durably but orders don’t need customers to exist conceptually (association, one-to-many); each line item exists only inside one order and dies with it (composition). Change any answer — “lines can transfer between orders” — and the arrow changes too. That sensitivity is why the notation matters.
Multiplicity Notation
1exactly one ·0..1optional ·*or0..*many ·1..*at least one.- Placed at the far end:
Customer 1 ──── 0..* Orderreads “one customer, zero-or-many orders.” - Multiplicity drives code:
0..1→ nullable/Optional;1→ constructor-required;1..*→ non-empty validation invariant.
Decision Procedure (fast, on whiteboard)
- Is it inheritance of identity or contract fulfillment? → triangles first.
- Does A merely receive B in a call? → dependency.
- Field reference? → association.
- Whole–part? Ask: does the part die when the whole dies? Yes → composition; No → aggregation.
Penalties Interviewers Apply
- Missing multiplicities on associations — expect the “can it be zero?” probe next.
- Filled vs hollow diamond swapped — signals memorized shapes without lifecycle reasoning.
- Dashed/solid triangle confusion — realization vs generalization reversed.
Premium Content
Unlock Class Diagrams and all premium lessons with a subscription.
From ₹199.99/year — See plans