Skip to content
Ameen Abozaid
PublishedBEG-025-L04

UML class diagrams, the useful 20%

  • Lesson 4 of 5
  • 10 min read
  • Beginner
On This Lesson 11 topics

Lesson Overview

You can now name how objects relate: association, aggregation, composition, dependency. In this lesson you learn to draw those relationships so that a teammate understands the design in half a minute. The drawing language is the class diagram of UML (Unified Modeling Language).

UML is large. We use only the small part that does most of the work in real projects: boxes for classes, lines for relationships, diamonds for ownership, a dashed arrow for dependency, and numbers for multiplicity. In the family of contacts picture, this is the family tree: it does not list every fact about every person, only who is related to whom.

Why this matters: backend teams sketch classes and tables on whiteboards and in design documents before they write code. A diagram that is correct, small, and readable settles design arguments early and later maps directly onto code and database tables.

This lesson builds on all previous lessons of this module. It uses plain text diagrams, so you can draw them anywhere.

Learning Objectives

By the end of this lesson you will be able to:

  • Draw a class as a box with a name and, optionally, a few key members.
  • Draw association, aggregation, composition, and dependency with the right line style.
  • Write multiplicity and role labels on the ends of a line.
  • Put the diamond on the correct end of a line.
  • Turn a short English description or a few Java classes into a diagram.
  • Decide what to leave out so the diagram stays readable.

Written Explanation

The class box

A class is a rectangle, divided if you wish into three compartments: the name, the fields, and the methods. In sketches, the member compartments are optional, and you list only members that matter for the point of the diagram.

text
+---------------------+
| Account             |
+---------------------+
| - balance : double  |
+---------------------+
| + deposit(amount)   |
| + withdraw(amount)  |
+---------------------+

- means private and + means public. A sketch that lists every field and every getter is the first mistake to avoid: Martin Fowler's advice on UML sketches is that the essence is being selective, because comprehensiveness works against comprehension. If the reader needs the exact fields, the code is the better place to look.

Lines and symbols

RelationshipLineWhere the symbol goes
AssociationSolid linenone (optional open arrow shows direction of knowing)
AggregationSolid lineHollow diamond on the whole's end
CompositionSolid lineFilled diamond on the whole's end
DependencyDashed line, open arrowheadArrow points at the class being used
InheritanceSolid lineHollow triangle at the parent
Interface implementationDashed lineHollow triangle at the interface

The diamond sits on the end of the container, the "whole", not the part. The Wikipedia class-diagram article describes aggregation as a hollow diamond and composition as a filled diamond on the containing class's end, and dependency as a dashed line with an open arrowhead from the dependent class to the one it depends on. The inheritance and interface rows come from the course's own scripts for this module and from common UML usage; we did not verify them against a primary page.

In plain text we draw the diamonds as ◇ (hollow) and ◆ (filled).

Multiplicity and roles

Put a number or range near each end of the line, saying how many objects of that end's class take part:

LabelMeaning
1exactly one
0..1zero or one
* or 0..*zero or more
1..*one or more

Read a line like a sentence from each end: Customer 1 --- * Account says "one customer is linked with many accounts" and "each account is linked with exactly one customer". You may also write a role name next to an end ("owner", "accounts") to say what the class is in that relationship.

What to include

  • Classes that matter for the design question you are answering.
  • The relationship between them, with its symbol and multiplicity.
  • A few key members, only when they explain something.
  • Dependencies only when they carry meaning.

Leave out getters, setters, constructors, standard-library types, and fields that merely repeat a relationship. A reference field such as List<Transaction> transactions is already shown by the line to Transaction: do not list it again inside the box.

Draw first, code second

A sketch costs minutes; a wrong design built in code costs days. Draw the classes and lines first, check the multiplicities against the description, and only then write the code. After coding, compare: every line in the diagram should be visible in the code, and every field link in the code should be a line on the diagram.

Examples

Example 1: customers, accounts, transactions (simple)

text
Customer 1 -------- * Account       (role of Customer: owner)
Account  1 ◆------- * Transaction   (role: transactions)

Read it: one customer is associated with many accounts. An account owns many transactions (filled diamond at the Account end): composition. The names Customer, Account, and Transaction are enough; no fields are needed to see the design.

Example 2: from code to diagram (practical)

Given this code (we compiled and ran it with JDK 21; the output was room 101 from 2026-03-01 and 1 room):

java
class Hotel {
    private final List<Room> rooms = new ArrayList<>();
    void addRoom(Room room) { rooms.add(room); }
}
class Booking {
    private final Room room;
    private final String checkIn;
    Booking(Room room, String checkIn) { this.room = room; this.checkIn = checkIn; }
}
class Guest {
    private final List<Booking> bookings = new ArrayList<>();
    void book(Room room, String checkIn) { bookings.add(new Booking(room, checkIn)); }
}

Work from the fields and the parameters:

  • Hotel receives existing Room objects through addRoom and holds a list: aggregation, one hotel to many rooms.
  • Guest creates its Booking objects itself in book and keeps them private: composition, one guest to many bookings.
  • Booking has a Room field: association, many bookings may refer to one room.
  • Guest.book(Room ...) only uses a room as a parameter, so no line is drawn for it.

Drawn one relationship per line, which is easy to keep in a text file:

text
Hotel   1 ◇------- * Room
Guest   1 ◆------- * Booking
Booking * -------- 1 Room

Each line comes from one field or one creating method, and each can be found in the code.

Example 3: from an English description (realistic)

A school has many classrooms. A teacher teaches many courses, and each course is taught by exactly one teacher. A course meets in at most one classroom, and a classroom can host many courses over the week.

  1. Find the nouns: School, Classroom, Teacher, Course.
  2. Find the "has" verbs and read the multiplicity from both ends.
  3. Decide the type: the school has classrooms that it owns (composition is reasonable); everything else is association.
text
School  1 ◆------- * Classroom
Teacher 1 -------- * Course
Course  * -------- 0..1 Classroom

The last line says each course has zero or one classroom, and each classroom has any number of courses. Two readers could draw School ◇ Classroom instead of ◆; both are fine when the reason is stated.

Backend Insight

Class diagrams are the bridge to databases. A line with 1 at one end and * at the other becomes a foreign key in the "many" table. Composition tends to become a table that cannot exist without its parent row. If your diagram is vague, your table design will be vague too.

Diagrams are also communication tools in code reviews and design documents. A diagram that fits on one page and shows only decisions is far more likely to stay in sync with the code than a complete one that nobody wants to update. If you keep diagrams in text form (as above, or in a diagram-as-text tool), they can live in the repository next to the code.

Common Mistakes

Mistake 1: Listing every field

A box with twenty fields drowns the relationships. Show the key members, or none.

Mistake 2: Diamond on the wrong end

The diamond belongs next to the whole. Transaction ◆---- Account says a transaction owns accounts.

Mistake 3: Forgetting multiplicities

A line without numbers does not say whether the link is one or many, which is the main thing a reader wants to know.

Mistake 4: Listing a relationship twice

Drawing Account ◆---- Transaction and also writing transactions : List<Transaction> in the box says the same thing twice and invites mismatches.

Mistake 5: A diagram that disagrees with the code

If the diagram says 1 and the code has a list, one of them is wrong. Fix whichever is wrong, not neither.

Exercises

Try each exercise yourself before opening the solutions.

Level A: Foundation

A1. What does each symbol mean: filled diamond, hollow diamond, dashed arrow?

Show solution A1

A1. Filled diamond: composition. Hollow diamond: aggregation. Dashed arrow: dependency.

A2. Read aloud, in both directions: Teacher 1 ---- * Course.

Show solution A2

A2. Left to right: one teacher is linked with many courses. Right to left: each course is linked with exactly one teacher.

A3. Which of these belong in a class box for a sketch: getName(), the key field balance, a constructor, the deposit method?

Show solution A3

A3. The key field balance and the method deposit. Getters and constructors clutter the box.

Level B: Application

B1. Draw (as text lines like the ones above) the relationships implied by this code:

java
class Playlist { private final List<Song> songs = new ArrayList<>();
                 void add(Song s) { songs.add(s); } }
class Song { private final Artist artist; Song(Artist a) { this.artist = a; } }
Show solution B1

B1.

text
Playlist 1 ◇------- * Song
Song     * -------- 1 Artist

Playlist receives existing songs through add, so aggregation; Song keeps an Artist in a field, so association.

B2. Draw from this description: "A cinema has several screens. A screening shows one film on one screen. A screening sells many tickets, and each ticket belongs to exactly one screening."

Show solution B2

B2. One reasonable answer:

text
Cinema    1 ◆------- * Screen
Screening * -------- 1 Screen
Screening * -------- 1 Film
Screening 1 ◆------- * Ticket

The cinema owns its screens. A screening is tied to one screen and one film. Tickets are created and owned by their screening, so composition. Judged on correct multiplicities and diamond on the whole's end.

B3. Find three problems in this diagram text: Order 1 ---- Customer, OrderLine ◆---- Order, and a box for Order that lists fourteen fields and all getters.

Show solution B3

B3. (1) No multiplicities on Order 1 ---- Customer (and it should read Order * ---- 1 Customer). (2) The diamond is on the part's end: it should be Order ◆---- OrderLine, with Order 1 and OrderLine *. (3) The Order box lists every field and getter, burying the relationships.

Level C: Challenge

C1. A Bank class has a method void send(Notifier n). Add this to the diagram of Bank 1 ◇---- * Customer and say whether you would draw it.

Show solution C1

C1. Bank - - -> Notifier as a dashed arrow, because send takes a Notifier as a parameter. Draw it only if the Bank-to-Notifier contract is part of the design point you are making. For a general diagram of the data model, leave it out.

C2. Draw from this description, giving every line a multiplicity and choosing diamonds with a reason: "A company has departments. Each department has employees. An employee can work in only one department, but may be part of many projects, and a project has many employees."

Show solution C2

C2.

text
Company    1 ◆------- * Department
Department 1 -------- * Employee
Employee   * -------- * Project

Departments live and die with the company (composition). Employees are associated with their one department and are not deleted with it in this model (a judgement call; state it). The employee-project link is many-to-many: * at both ends. A many-to-many link needs special care in code and in databases, which later modules cover.

Mini Challenge

Draw a diagram, in text, for an online library of audiobooks from this description: "A catalogue contains many titles. A member has one subscription and borrows many titles over time. Each borrowing records a date." Include classes, relationship types, multiplicities, and at most two key members per class.

Check your work: no box has more than two members, every line has two multiplicities, and each diamond sits on the whole's end.

Summary & Next Lesson

Key takeaways

  • A class is a box with a name; list only key members.
  • A solid line is an association. A hollow diamond on the whole's end means aggregation; a filled diamond means composition; a dashed arrow means dependency.
  • Write multiplicity (1, 0..1, *, 1..*) on both ends of every line.
  • Leave out getters, constructors, and fields that repeat a line.
  • Draw first, code second, then check that diagram and code agree.

Next lesson

The next lesson, "Demo: drawing the UML, then coding Customer and Account", is a follow-along demo: you draw the diagram for the bank, then write the code from it, including one deliberate mistake with a back link.

Self-check

  1. Which end of a composition line carries the filled diamond?
  2. What does 0..1 mean?
  3. How is a dependency drawn?
  4. Name two things to leave out of a sketch box.
  5. How do you check a finished diagram against code?
Show answers
  1. The whole's end (the owner).
  2. Zero or one.
  3. As a dashed line with an arrow pointing at the class being used.
  4. For example getters, constructors, fields that already appear as lines.
  5. Every line should appear as a field or method in the code, and every association field should appear as a line.

References

  • Wikipedia, Class diagram. Supports hollow diamond for aggregation and filled diamond for composition on the containing class's end, the dashed open-arrow dependency, and multiplicity ranges such as 0..1, *, and 1..*.
  • Martin Fowler, UML as Sketch. Supports the advice to sketch only what matters and that sketches need not follow every UML rule.
  • Mermaid, Class diagrams. Shows that text-based diagram tools support these same relationship types and the multiplicity values 1, 0..1, 1..*, and *.
  • Inheritance and interface-implementation symbols are not verified from a fetched source. The Java code in this lesson was compiled and run with JDK 21.

Practice

Apply this lesson with the module's lab, exercises and quiz.

Lab and exercises Quiz

Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.

Continue to next lesson

Type to search levels, phases, modules and lessons.