UML Class Diagrams


Detailed description

UML class diagram with 6 classes (Customer, VIP, Guest, Order, LineItem, Product), 1 interface (Billable). VIP extends Customer. Guest extends Customer. Order implements Billable. Customer is associated with Order with multiplicity one to many. Order composes LineItem with multiplicity one to one or more. LineItem is associated with Product with multiplicity many to one.

Classes

  • Customer — Attributes: private id: int; private name: String — Operations: public placeOrder(): void
  • VIP — Attributes: none declared — Operations: none declared
  • Guest — Attributes: none declared — Operations: none declared
  • Order — Attributes: private date: Date; private status: String — Operations: public calcTotal(): float
  • LineItem — Attributes: private quantity: int — Operations: none declared
  • Product — Attributes: private price: float; private name: String — Operations: none declared

Interfaces

  • Billable — Attributes: none declared — Operations: public processPayment(): bool

Relationships

  • VIP extends Customer
  • Guest extends Customer
  • Order implements Billable
  • Customer is associated with Order with multiplicity one to many
  • Order composes LineItem with multiplicity one to one or more
  • LineItem is associated with Product with multiplicity many to one

Introduction

Pedagogical Note: This chapter is designed using principles of Active Engagement (frequent retrieval practice). We will build concepts incrementally. Please complete the “Quick Checks” without looking back at the text—this introduces a “desirable difficulty” that strengthens long-term memory.

🎯 Learning Objectives

By the end of this chapter, you will be able to:

  1. Translate real-world object relationships into UML Class Diagrams.
  2. Differentiate between structural relationships (Association, Aggregation, Composition).
  3. Read and interpret system architecture from UML class diagrams.

Diagram – The Blueprint of Software

Imagine you are an architect designing a complex building. Before laying a single brick, you need blueprints. In software engineering, we use similar models. The Unified Modeling Language (UML) is the most common one. Among UML diagrams, Class Diagrams are the most common ones, because they are very close to the code. They describe the static structure of a system by showing the system’s classes, their attributes, operations (methods), and the relationships among objects.

The Core Building Blocks

2.1 Classes

A Class is a template for creating objects. In UML, a class is represented by a rectangle divided into three compartments:

  1. Top: The Class Name.
  2. Middle: Attributes (variables/state).
  3. Bottom: Operations (methods/behavior).

2.2 Modifiers (Visibility)

To enforce encapsulation, UML uses symbols to define who can access attributes and operations:

  • + Public: Accessible from anywhere.
  • - Private: Accessible only within the class.
  • # Protected: Accessible within the class and its subclasses.
  • ~ Package/Default: Accessible by any class in the same package.

Detailed description

UML class diagram with 1 class (User).

Classes

  • User — Attributes: private username: String; private email: String; protected id: int — Operations: public login(): boolean; public resetPassword(): void

2.3 Interfaces

An Interface represents a contract. It tells us what a class must do, but not how it does it. It is denoted by the <<interface>> stereotype. Interfaces contain method signatures and usually do not declare attributes (the UML specification allows it, but I recommend not to use it)

Detailed description

UML class diagram with 1 interface (Payable).

Interfaces

  • Payable — Attributes: none declared — Operations: public processPayment(): bool

Quick Check 1 (Retrieval Practice) Cover the screen above. What do the symbols +, -, and # stand for? Why does an interface lack an attributes compartment?

Connecting the Dots: Relationships

Software is never just one class working in isolation. Classes interact. We represent these interactions with different types of lines and arrows.

Generalization — “Is-A” Relationships

Generalization connects a subclass to a superclass. It means the subclass inherits attributes and behaviors from the parent.

  • UML Symbol: A solid line with a hollow, closed arrow pointing to the parent.

Interface Realization

When a class agrees to implement the methods defined in an interface, it “realizes” the interface.

  • UML Symbol: A dashed line with a hollow, closed arrow pointing to the interface.

Detailed description

UML class diagram with 3 classes (Car, Sedan, SUV), 1 interface (Vehicle). Car implements Vehicle. Sedan extends Car. SUV extends Car.

Classes

  • Car — Attributes: private make: String — Operations: public startEngine(): void
  • Sedan — Attributes: none declared — Operations: none declared
  • SUV — Attributes: none declared — Operations: none declared

Interfaces

  • Vehicle — Attributes: none declared — Operations: public startEngine(): void

Relationships

  • Car implements Vehicle
  • Sedan extends Car
  • SUV extends Car

Dependency (Weakest Relationship)

A dependency indicates that one class uses another, but does not hold a permanent reference to it. For example, a class might use another class as a method parameter, local variable, or return type. Dependency is the weakest relationship in a class diagram.

  • UML Symbol: A dashed line with an open arrowhead.

Detailed description

UML class diagram with 2 classes (Train, ButtonPressedEvent). Train depends on ButtonPressedEvent.

Classes

  • Train — Attributes: none declared — Operations: protected addStop(stop: ButtonPressedEvent): void; public startTrain(velocity: double): void
  • ButtonPressedEvent — Attributes: none declared — Operations: none declared

Relationships

  • Train depends on ButtonPressedEvent

In this example, Train depends on ButtonPressedEvent because it uses it as a parameter type in addStop(). However, Train does not store a permanent reference to ButtonPressedEvent—the dependency exists only for the duration of the method call.

Here is another example where a class depends on an exception it throws:

Detailed description

UML class diagram with 2 classes (ChecksumValidator, InvalidChecksumException). ChecksumValidator depends on InvalidChecksumException.

Classes

  • ChecksumValidator — Attributes: none declared — Operations: public execute(): bool; public validate(): void
  • InvalidChecksumException — Attributes: none declared — Operations: none declared

Relationships

  • ChecksumValidator depends on InvalidChecksumException

Association — “Has-A” / “Knows-A” Relationships

A basic structural relationship indicating that objects of one class are connected to objects of another (e.g., a “Teacher” knows about a “Student”). Attributes can also be represented as association lines: a line is drawn between the owning class and the target attribute’s class, providing a quick visual indication of which classes are related.

  • UML Symbol: A simple solid line.
  • You can also name associations and make them directional using an arrowhead to indicate navigability (which class holds a reference to the other).

Detailed description

UML class diagram with 2 classes (Student, Course). Student is associated with Course with multiplicity many to one or more labeled "enrolled in".

Classes

  • Student — Attributes: private name: String — Operations: none declared
  • Course — Attributes: private title: String — Operations: none declared

Relationships

  • Student is associated with Course with multiplicity many to one or more labeled "enrolled in"

Multiplicities

Along association lines, we use numbers to define how many objects are involved. Always show multiplicity on both ends of an association.

Notation Meaning
1 Exactly one
0..1 Zero or one (optional)
* or 0..* Zero to many
1..* One to many (at least one required)

Detailed description

UML class diagram with 2 classes (Author, Book). Author is associated with Book with multiplicity one to one or more labeled "writes".

Classes

  • Author — Attributes: none declared — Operations: none declared
  • Book — Attributes: none declared — Operations: none declared

Relationships

  • Author is associated with Book with multiplicity one to one or more labeled "writes"

When neither end of an association is annotated with an arrowhead or X mark, navigability is formally undefined in UML 2.5. By convention, many authors and tools render this case as bidirectional (both classes know about each other), but you should not rely on the default — make navigability explicit when it matters. In practice, the relationship is often one-way: only one class holds a reference to the other. UML uses arrowheads and X marks to show this navigability.

  • Navigable end An open arrowhead pointing to the class that can be “reached”. The left object has a reference to the right object.
  • Non-Navigable end An X on the end that cannot be navigated. This explicitly states that the class at the X end does not hold a reference to the other.

Here are the four navigability combinations, each with an example:

Unidirectional (one arrowhead): Only one class holds a reference.

Detailed description

UML class diagram with 2 classes (Vote, Politician). Vote references Politician.

Classes

  • Vote — Attributes: none declared — Operations: none declared
  • Politician — Attributes: none declared — Operations: none declared

Relationships

  • Vote references Politician

Vote holds a reference to Politician, but Politician does not know about individual Vote objects.

Bidirectional (arrowheads on both ends): Both classes hold a reference to each other.

Detailed description

UML class diagram with 2 classes (Employee, Boss). Employee and Boss reference each other.

Classes

  • Employee — Attributes: none declared — Operations: none declared
  • Boss — Attributes: none declared — Operations: none declared

Relationships

  • Employee and Boss reference each other

Employee knows about their Boss, and Boss knows about their Employee. Note that a plain line with no arrowheads on either end has unspecified navigability per UML 2.5 — not “bidirectional by default.” If you mean both directions are navigable, draw arrowheads on both ends (as above) to make that explicit.

Non-navigable on one end (X on one side): One class is explicitly prevented from navigating.

Detailed description

UML class diagram with 2 classes (Voter, Vote). Voter has a non-navigable association with Vote.

Classes

  • Voter — Attributes: none declared — Operations: none declared
  • Vote — Attributes: none declared — Operations: none declared

Relationships

  • Voter has a non-navigable association with Vote

In the full UML notation, an X on the Voter end means that the opposite lifeline cannot navigate to it — i.e., Vote does not hold a reference back to Voter. (Voter’s navigability toward Vote is then determined by whatever is marked on the Vote end.) Note: the X mark is a formal UML 2 notation that many simplified tools do not render, and per UML 2.5, when one end carries a navigability arrow but the other end is unmarked, the unmarked end’s navigability is formally undefined, not “non-navigable” by default.

Non-navigable on both ends (X on both sides): Neither class holds a reference—the association is recorded only in the model, not in code.

Detailed description

UML class diagram with 2 classes (Account, ClearTextPassword). Account and ClearTextPassword have a non-navigable association.

Classes

  • Account — Attributes: none declared — Operations: none declared
  • ClearTextPassword — Attributes: none declared — Operations: none declared

Relationships

  • Account and ClearTextPassword have a non-navigable association

An X on both ends of AccountClearTextPassword means neither class should store a reference to the other. This is a deliberate design decision (e.g., for security: an Account should never hold a reference to a ClearTextPassword).

When to use navigability: Navigability is a design-level detail. In analysis/domain models, plain associations (no arrowheads) are preferred because you haven’t decided which class holds the reference yet. Once you move into detailed design, add navigability to show which class stores the reference—this maps directly to code (a field/attribute in the class at the arrow tail).

Aggregation (“Owns-A”)

A specialized association where one class belongs to a collection, but the parts can exist independently of the whole. If a University closes down, the Professors still exist. Think of aggregation as a long-term, whole-part association.

  • UML Symbol: A solid line with an empty diamond at the “whole” end.

Detailed description

UML class diagram with 2 classes (University, Professor). University aggregates Professor with multiplicity one to many.

Classes

  • University — Attributes: none declared — Operations: none declared
  • Professor — Attributes: none declared — Operations: none declared

Relationships

  • University aggregates Professor with multiplicity one to many

Composition (“Is-Made-Up-Of”)

A strict relationship where the parts cannot exist without the whole. If you destroy a House, the Rooms inside it are also destroyed. A part may belong to only one composite at a time (exclusive ownership), and the composite has sole responsibility for the lifetime of its parts.

  • UML Symbol: A solid line with a filled diamond at the “whole” end.
  • Per the UML spec, the multiplicity on the composite end must be 1 or 0..1.

Detailed description

UML class diagram with 2 classes (House, Room). House composes Room with multiplicity one to one or more.

Classes

  • House — Attributes: none declared — Operations: none declared
  • Room — Attributes: none declared — Operations: none declared

Relationships

  • House composes Room with multiplicity one to one or more

A helpful way to think about the difference: In C++, aggregation is usually expressed through pointers/references (the part can exist separately), while composition is expressed by containing instances by value (the part’s lifetime is tied to the whole). In Java and Python, every object reference is effectively a pointer — the distinction between aggregation and composition is communicated through design intent (who created the part? who destroys it?) rather than through language syntax. Inner classes in Java are one indicator of composition but are not required.

⚠ Honest caveat on aggregation. Aggregation has intentionally informal semantics in the UML 2 specification. Martin Fowler (UML Distilled) observes: “Aggregation is strictly meaningless; as a result, I recommend that you ignore it in your own diagrams.” When you aren’t sure whether something is aggregation or plain association, use association — it is always safe. Reserve the hollow diamond for the cases where part-whole semantics clearly add communicative value.

Quick Check 2 (Self-Explanation) In your own words, explain the difference between the empty diamond (Aggregation) and the filled diamond (Composition). Give a real-world example of each that is not mentioned in this text.

Relationship Strength Summary

From weakest to strongest, the class relationships are:

RelationshipSymbolMeaningExample
Dependency Dashed arrow"uses" temporarilyMethod parameter, thrown exception
Association Solid line"knows about" structurallyEmployee knows about Boss
Aggregation Hollow diamond"has-a" (parts can exist alone)Library has Books
Composition Filled diamond"made up of" (parts die with whole)House is made of Rooms
Generalization Hollow triangle"is-a" (inheritance)Car is-a Vehicle
Realization Dashed hollow triangle"implements" (interface)Car implements Drivable

⚠ The Five Most Common UML Class Diagram Mistakes

Empirical studies of student diagrams (Chren et al., “Mistakes in UML Diagrams: Analysis of Student Projects in a Software Engineering Course”, ICSE SEET 2019) identify these recurring errors. Watch for them in your own work:

# Mistake Fix
1 Generalization arrow pointed the wrong way — triangle at the child instead of the parent The triangle always rests at the parent. Sanity-check with the “is-a” sentence: “A [child] is a [parent]”.
2 Multiplicity on the wrong end — e.g., * placed next to the “one” side Multiplicity answers “for one of the opposite class, how many of this class?” Place it next to the class being quantified.
3 Missing multiplicity on one end Per Ambler (G117), always show multiplicity on both ends of every relationship. An unlabeled end is ambiguous, not “just 1.”
4 Confusing aggregation and composition — using the filled diamond when parts are actually shared Composition = exclusive ownership and lifecycle dependency. If the part can exist without the whole, use aggregation (or plain association).
5 Verbose 0..* when * suffices Use the shorthand * for zero-or-more. The UML spec defines them as identical; * is more concise. Reserve 0..* only when contrasting explicitly with 1..* nearby.

Pedagogy tip: Before turning in any class diagram, run this five-item checklist over every relationship. Catching these five mistakes catches the majority of grading-level errors.

Advanced Class Notation

Abstract Classes and Operations

An abstract class is a class that cannot be instantiated directly—it serves as a base for subclasses. In UML, an abstract class is indicated by italicizing the class name or adding {abstract}.

An abstract operation is a method with no implementation, intended to be supplied by descendant classes. Abstract operations are shown by italicizing the operation name.

Detailed description

UML class diagram with 1 class (Rectangle), 1 abstract class (Shape). Rectangle extends Shape.

Classes

  • Rectangle — Attributes: private width: int; private length: int — Operations: public setWidth(width: int): void; public setHeight(height: int): void; public draw(): void

Abstract classes

  • Shape — Attributes: private color: int — Operations: public setColor(r: int, g: int, b: int): void; + draw(): void (abstract)

Relationships

  • Rectangle extends Shape

In this example, Shape is abstract (it cannot be created directly) and declares an abstract draw() method. Rectangle inherits from Shape and provides a concrete implementation of draw().

Static Members

Static (class-level) attributes and operations belong to the class itself rather than to individual instances. In UML, static members are shown underlined.

Detailed description

UML class diagram with 1 class (MathUtils).

Classes

  • MathUtils — Attributes: +PI: double (static) — Operations: +abs(n: int): int (static); public round(n: double): int

From Code to Diagram: Worked Examples

A key skill is translating between code and UML class diagrams. Let’s work through several examples that progressively build this skill.

Example 1: A Simple Class

public class BaseSynchronizer {
    public void synchronizationStarted() { }
}
class BaseSynchronizer {
public:
    void synchronizationStarted() { }
};
class BaseSynchronizer:
    def synchronization_started(self) -> None:
        pass
class BaseSynchronizer {
  synchronizationStarted(): void { }
}

Detailed description

UML class diagram with 1 class (BaseSynchronizer).

Classes

  • BaseSynchronizer — Attributes: none declared — Operations: public synchronizationStarted(): void

Each public method becomes a + operation in the bottom compartment. The return type follows a colon after the method signature.

Example 2: Attributes and Associations

When a class holds a reference to another class, you can show it either as an attribute or as an association line (but be consistent throughout your diagram).

public class Student {
    Roster roster;

    public void storeRoster(Roster r) {
        roster = r;
    }
}

class Roster { }
class Roster { };

class Student {
public:
    void storeRoster(Roster& r) {
        roster = &r;
    }

private:
    Roster* roster = nullptr;
};
class Roster:
    pass


class Student:
    def __init__(self) -> None:
        self._roster: Roster | None = None

    def store_roster(self, roster: Roster) -> None:
        self._roster = roster
class Roster { }

class Student {
  private roster?: Roster;

  storeRoster(roster: Roster): void {
    this.roster = roster;
  }
}

Detailed description

UML class diagram with 2 classes (Student, Roster). Student references Roster.

Classes

  • Student — Attributes: package roster: Roster — Operations: public storeRoster(r: Roster): void
  • Roster — Attributes: none declared — Operations: none declared

Relationships

  • Student references Roster

Notice: in the Java version, the roster field has package visibility (~) because no access modifier was specified (Java default is package-private). Other languages express visibility differently, but the relationship is the same: Student holds a reference to a Roster.

Example 3: Dependency from Exception Handling

public class ChecksumValidator {
    public boolean execute() {
        try {
            this.validate();
        } catch (InvalidChecksumException e) {
            // handle error
        }
        return true;
    }
    public void validate() throws InvalidChecksumException { }
}

class InvalidChecksumException extends Exception { }
#include <exception>

class InvalidChecksumException : public std::exception { };

class ChecksumValidator {
public:
    bool execute() {
        try {
            validate();
        } catch (const InvalidChecksumException&) {
            // handle error
        }
        return true;
    }

    void validate() { }
};
class InvalidChecksumException(Exception):
    pass


class ChecksumValidator:
    def execute(self) -> bool:
        try:
            self.validate()
        except InvalidChecksumException:
            # handle error
            pass
        return True

    def validate(self) -> None:
        pass
class InvalidChecksumException extends Error { }

class ChecksumValidator {
  execute(): boolean {
    try {
      this.validate();
    } catch (error) {
      if (!(error instanceof InvalidChecksumException)) throw error;
      // handle error
    }
    return true;
  }

  validate(): void { }
}

Detailed description

UML class diagram with 2 classes (ChecksumValidator, InvalidChecksumException). ChecksumValidator depends on InvalidChecksumException.

Classes

  • ChecksumValidator — Attributes: none declared — Operations: public execute(): bool; public validate(): void
  • InvalidChecksumException — Attributes: none declared — Operations: none declared

Relationships

  • ChecksumValidator depends on InvalidChecksumException

The ChecksumValidator depends on InvalidChecksumException (it uses it in a throws clause and catch block) but does not store a permanent reference to it. This is a dependency, not an association.

Example 4: Composition from Inner Classes

public class MotherBoard {
    private class IDEBus { }

    private final IDEBus primaryIDE = new IDEBus();
    private final IDEBus secondaryIDE = new IDEBus();
}
class MotherBoard {
    class IDEBus { };

    IDEBus primaryIDE;
    IDEBus secondaryIDE;
};
class MotherBoard:
    class _IDEBus:
        pass

    def __init__(self) -> None:
        self._primary_ide = MotherBoard._IDEBus()
        self._secondary_ide = MotherBoard._IDEBus()
class IDEBus { }

class MotherBoard {
  private readonly primaryIDE = new IDEBus();
  private readonly secondaryIDE = new IDEBus();
}

Detailed description

UML class diagram with 2 classes (MotherBoard, IDEBus). MotherBoard composes IDEBus with multiplicity one to 2.

Classes

  • MotherBoard — Attributes: private primaryIDE: IDEBus; private secondaryIDE: IDEBus — Operations: none declared
  • IDEBus — Attributes: none declared — Operations: none declared

Relationships

  • MotherBoard composes IDEBus with multiplicity one to 2

The private part type plus owned fields indicate composition: the IDEBus instances are created and controlled by the MotherBoard.

Quick Check (Generation): Before looking at the answer below, try to draw the UML class diagram for this code:

import java.util.ArrayList;
import java.util.List;
public class Division {
    private List<Employee> division = new ArrayList<>();
    private Employee[] employees = new Employee[10];
}
Reveal Answer

Detailed description

UML class diagram with 2 classes (Division, Employee). Division aggregates Employee with multiplicity one to many. Division is associated with Employee with multiplicity one to 10.

Classes

  • Division — Attributes: private division: List~Employee~; private employees: Employee[] — Operations: none declared
  • Employee — Attributes: none declared — Operations: none declared

Relationships

  • Division aggregates Employee with multiplicity one to many
  • Division is associated with Employee with multiplicity one to 10
The List<Employee> field suggests aggregation (the collection can grow dynamically, employees can exist independently). The array with a fixed size of 10 is a direct association with a specific multiplicity.

Putting It All Together: The E-Commerce System

Pedagogical Note: We are now combining isolated concepts into a complex schema. This reflects how you will encounter UML in the real world.

Let’s read the architectural blueprint for a simplified E-Commerce system.

Detailed description

UML class diagram with 6 classes (Customer, VIP, Guest, Order, LineItem, Product), 1 interface (Billable). VIP extends Customer. Guest extends Customer. Order implements Billable. Customer is associated with Order with multiplicity one to many. Order composes LineItem with multiplicity one to one or more. LineItem is associated with Product with multiplicity many to one.

Classes

  • Customer — Attributes: private id: int; private name: String — Operations: public placeOrder(): void
  • VIP — Attributes: none declared — Operations: none declared
  • Guest — Attributes: none declared — Operations: none declared
  • Order — Attributes: private date: Date; private status: String — Operations: public calcTotal(): float
  • LineItem — Attributes: private quantity: int — Operations: none declared
  • Product — Attributes: private price: float; private name: String — Operations: none declared

Interfaces

  • Billable — Attributes: none declared — Operations: public processPayment(): bool

Relationships

  • VIP extends Customer
  • Guest extends Customer
  • Order implements Billable
  • Customer is associated with Order with multiplicity one to many
  • Order composes LineItem with multiplicity one to one or more
  • LineItem is associated with Product with multiplicity many to one

System Walkthrough:

  1. Generalization: VIP and Guest are specific types of Customer.
  2. Association (Multiplicity): 1 Customer can have * (zero to many) Orders.
  3. Interface Realization: Order implements the Billable interface.
  4. Composition: An Order strongly contains 1..* (one or more) LineItems. If the order is deleted, the line items are deleted.
  5. Association: Each LineItem points to exactly 1 Product.

Real-World Examples

The following examples apply everything from this chapter to systems you interact with every day. Try reading each diagram yourself before the walkthrough — this is retrieval practice in action.

Example 1: Spotify — Music Streaming Domain Model

Scenario: An analysis-level domain model for a music streaming service. The goal is to capture what things are and how they relate — not implementation details like database schemas or network calls.

Detailed description

UML class diagram with 6 classes (User, FreeUser, PremiumUser, Playlist, Track, Artist). FreeUser extends User. PremiumUser extends User. User composes Playlist with multiplicity one to many labeled "owns". Playlist aggregates Track with multiplicity many to many labeled "contains". Track is associated with Artist with multiplicity many to one or more labeled "performedBy".

Classes

  • User — Attributes: none declared — Operations: public search(query: String): list; public createPlaylist(name: String): Playlist
  • FreeUser — Attributes: none declared — Operations: none declared
  • PremiumUser — Attributes: none declared — Operations: public download(track: Track): void
  • Playlist — Attributes: none declared — Operations: public addTrack(t: Track): void
  • Track — Attributes: public title: String; public duration: int — Operations: none declared
  • Artist — Attributes: public name: String — Operations: none declared

Relationships

  • FreeUser extends User
  • PremiumUser extends User
  • User composes Playlist with multiplicity one to many labeled "owns"
  • Playlist aggregates Track with multiplicity many to many labeled "contains"
  • Track is associated with Artist with multiplicity many to one or more labeled "performedBy"

What the UML notation captures:

  1. Generalization (hollow triangle): FreeUser and PremiumUser both extend User, inheriting search() and createPlaylist(). Only PremiumUser adds download() — a capability unlocked by upgrading. The hollow triangle always points up toward the parent class.
  2. Composition (filled diamond, User → Playlist): A User owns their playlists. Deleting a user account deletes their playlists — the parts cannot outlive the whole. The filled diamond sits on the owner’s side.
  3. Aggregation (hollow diamond, Playlist → Track): A Playlist contains tracks, but tracks exist independently — the same track can appear in many playlists. Deleting a playlist does not remove the track from the catalog.
  4. Association with multiplicity (Track → Artist): Each track is performed by 1..* artists — at least one (solo) or more (collaboration). This multiplicity directly encodes a real business rule.

Analysis vs. design level: This diagram has no visibility modifiers (+, -). That is intentional — at the analysis level we model what things are and do, not encapsulation decisions. Visibility is a design-level concern added in a later phase.

Example 2: GitHub — Pull Request Design Model

Scenario: A design-level diagram (note the visibility modifiers) showing how GitHub’s code review system could be modeled internally. Notice how an interface creates a formal contract between components.

Detailed description

UML class diagram with 4 classes (Repository, PullRequest, Review, CICheck), 1 interface (Mergeable). PullRequest implements Mergeable. Repository composes PullRequest with multiplicity one to many. PullRequest composes Review with multiplicity one to many. PullRequest depends on CICheck.

Classes

  • Repository — Attributes: private name: String; private isPrivate: bool — Operations: public openPR(title: String): PullRequest
  • PullRequest — Attributes: private title: String; private status: String — Operations: public addReview(r: Review): void; public canMerge(): bool; public merge(): void
  • Review — Attributes: private verdict: String — Operations: public approve(): void; public requestChanges(): void
  • CICheck — Attributes: private passed: bool — Operations: public getResult(): bool

Interfaces

  • Mergeable — Attributes: none declared — Operations: public canMerge(): bool; public merge(): void

Relationships

  • PullRequest implements Mergeable
  • Repository composes PullRequest with multiplicity one to many
  • PullRequest composes Review with multiplicity one to many
  • PullRequest depends on CICheck

What the UML notation captures:

  1. Interface Realization (dashed hollow arrow): PullRequest implements Mergeable — a contract committing the class to provide canMerge() and merge(). A merge pipeline can work with any Mergeable object without knowing the concrete type.
  2. Composition (Repository → PullRequest): A PR cannot exist without its repository. Delete the repo, and all its PRs are deleted — the filled diamond on Repository’s side shows ownership.
  3. Composition (PullRequest → Review): A review only exists in the context of one PR. 1 *-- * reads: one PR can have zero or more reviews; each review belongs to exactly one PR.
  4. Dependency (dashed open arrow, PullRequest → CICheck): PullRequest uses CICheck temporarily — perhaps receiving it as a method parameter. It does not hold a permanent field reference, so this is a dependency, not an association.

Example 3: Uber Eats — Food Delivery Domain Model

Scenario: The domain model for a food delivery platform. This example is excellent for practicing multiplicity — every 0..1, 1, and * encodes a real business rule the engineering team must enforce.

Detailed description

UML class diagram with 6 classes (Customer, Order, OrderItem, MenuItem, Restaurant, Driver). Customer is associated with Order with multiplicity one to many labeled "places". Order composes OrderItem with multiplicity one to one or more labeled "contains". OrderItem is associated with MenuItem with multiplicity many to one labeled "references". Restaurant is associated with MenuItem with multiplicity one to one or more labeled "offers". Driver is associated with Order with multiplicity zero or one to zero or one labeled "delivers".

Classes

  • Customer — Attributes: private name: String; private address: String — Operations: none declared
  • Order — Attributes: private placedAt: DateTime; private status: String — Operations: public calcTotal(): float
  • OrderItem — Attributes: private quantity: int; private unitPrice: float — Operations: none declared
  • MenuItem — Attributes: private name: String; private price: float — Operations: none declared
  • Restaurant — Attributes: private name: String; private rating: float — Operations: none declared
  • Driver — Attributes: private name: String; private vehicleType: String — Operations: none declared

Relationships

  • Customer is associated with Order with multiplicity one to many labeled "places"
  • Order composes OrderItem with multiplicity one to one or more labeled "contains"
  • OrderItem is associated with MenuItem with multiplicity many to one labeled "references"
  • Restaurant is associated with MenuItem with multiplicity one to one or more labeled "offers"
  • Driver is associated with Order with multiplicity zero or one to zero or one labeled "delivers"

What the UML notation captures:

  1. Customer "1" -- "*" Order: One customer can have zero orders (a new account) or many. The navigability arrow shows Customer holds the reference — in code, a Customer would have an orders collection field.
  2. Composition (Order → OrderItem): Order items only exist within an order. Cancelling the order destroys the items. The 1..* on OrderItem enforces that every order must have at least one item.
  3. OrderItem "*" -- "1" MenuItem: Each item references exactly one menu item. Many orders can reference the same menu item — deleting an order does not remove the menu item from the restaurant’s catalog.
  4. Driver "0..1" -- "0..1" Order: A driver handles at most one active delivery at a time; an order has at most one assigned driver. Before dispatch, both sides satisfy 0 — neither requires the other to exist yet. This captures a real business constraint in two characters.

Example 4: Netflix — Content Catalogue Model

Scenario: Netflix serves two fundamentally different types of content — movies (watched once) and TV shows (composed of seasons and episodes). This diagram shows how inheritance and composition work together to model a content catalog.

Detailed description

UML class diagram with 4 classes (Movie, Season, Episode, Genre), 2 abstract classes (Content, TVShow). Movie extends Content. TVShow extends Content. TVShow composes Season with multiplicity one to one or more labeled "contains". Season composes Episode with multiplicity one to one or more labeled "contains". Content is associated with Genre with multiplicity many to one or more labeled "classifiedBy".

Classes

  • Movie — Attributes: private duration: int — Operations: public play(): void
  • Season — Attributes: private seasonNumber: int — Operations: none declared
  • Episode — Attributes: private episodeNumber: int; private duration: int — Operations: public play(): void
  • Genre — Attributes: private name: String — Operations: none declared

Abstract classes

  • Content — Attributes: protected title: String; protected rating: String — Operations: + play(): void (abstract)
  • TVShow — Attributes: none declared — Operations: none declared

Relationships

  • Movie extends Content
  • TVShow extends Content
  • TVShow composes Season with multiplicity one to one or more labeled "contains"
  • Season composes Episode with multiplicity one to one or more labeled "contains"
  • Content is associated with Genre with multiplicity many to one or more labeled "classifiedBy"

What the UML notation captures:

  1. Abstract class (abstract class Content): The italicised class name and {abstract} on play() signal that Content is never instantiated directly — you never watch a “content”, only a Movie or an Episode. Movie overrides play() with its own implementation. TVShow is also abstract (it inherits play() without overriding it) — you don’t play a show as a whole, you play one of its Episodes, which provides its own concrete play().
  2. Generalization hierarchy: Both Movie and TVShow extend Content, inheriting title and rating. A Movie adds duration directly; a TVShow delegates duration implicitly through its episodes.
  3. Nested composition (TVShow → Season → Episode): A TVShow is composed of seasons; each season is composed of episodes. Delete a show and the seasons disappear; delete a season and the episodes disappear. The chain of filled diamonds models this cascade.
  4. Association with multiplicity (Content → Genre): A movie or show belongs to 1..* genres (at least one — e.g., Action). A genre classifies * content items. This is a plain association — deleting a genre does not delete the content.

Example 5: Strategy Pattern — Pluggable Payment Processing

Scenario: A shopping cart needs to support multiple payment methods (credit card, PayPal, crypto) and let users switch between them at runtime. This is the Strategy design pattern — and a class diagram is the canonical way to document it.

Detailed description

UML class diagram with 4 classes (CreditCardPayment, PayPalPayment, CryptoPayment, ShoppingCart), 1 interface (PaymentStrategy). CreditCardPayment implements PaymentStrategy. PayPalPayment implements PaymentStrategy. CryptoPayment implements PaymentStrategy. ShoppingCart references PaymentStrategy labeled "uses".

Classes

  • CreditCardPayment — Attributes: private cardNumber: String; private cvv: String — Operations: public pay(amount: float): bool; public refund(amount: float): bool
  • PayPalPayment — Attributes: private email: String — Operations: public pay(amount: float): bool; public refund(amount: float): bool
  • CryptoPayment — Attributes: private walletAddress: String — Operations: public pay(amount: float): bool; public refund(amount: float): bool
  • ShoppingCart — Attributes: private items: list; private strategy: PaymentStrategy — Operations: public setPayment(s: PaymentStrategy): void; public checkout(): bool

Interfaces

  • PaymentStrategy — Attributes: none declared — Operations: public pay(amount: float): bool; public refund(amount: float): bool

Relationships

  • CreditCardPayment implements PaymentStrategy
  • PayPalPayment implements PaymentStrategy
  • CryptoPayment implements PaymentStrategy
  • ShoppingCart references PaymentStrategy labeled "uses"

What the UML notation captures:

  1. Interface as contract: PaymentStrategy defines the contract — pay() and refund(). Every concrete implementation must provide both. The interface appears at the top of the hierarchy, with implementors below.
  2. **Three realizations (.. >):** CreditCardPayment, PayPalPayment, and CryptoPayment all implement PaymentStrategy. The dashed hollow arrow points toward the interface each class promises to fulfill.
  3. Association ShoppingCart --> PaymentStrategy: The cart holds a reference to PaymentStrategy — not to any specific implementation. This navigability arrow (open head, not filled diamond) means ShoppingCart has a field of type PaymentStrategy. Crucially, it is typed to the interface, not a concrete class.
  4. The power of this design: Because ShoppingCart depends on PaymentStrategy (the interface), you can call cart.setPayment(new CryptoPayment()) at runtime and the cart works without any changes to its own code. The class diagram makes this extensibility visible — and it shows exactly where the seam between context and strategy is.

Connection to practice: This is the same pattern behind Java’s Comparator, Python’s sort(key=...), and every payment SDK you will ever integrate in your career. Class diagrams let you see the shape of the pattern independent of any language.

5. Chapter Review & Spaced Practice

To lock this information into your long-term memory, do not skip this section!

Active Recall Challenge: Grab a blank piece of paper. Without looking at this chapter, try to draw the UML Class Diagram for the following scenario:

  1. A School is composed of one or many Departments (If the school is destroyed, departments are destroyed).
  2. A Department aggregates many Teachers (Teachers can exist without the department).
  3. Teacher is a subclass of an Employee class.
  4. The Employee class has a private attribute salary and a public method getDetails().

Review your drawing against the rules in sections 2 and 3. How did you do? Identifying your own gaps in knowledge is the most powerful step in the learning process!

6. Practice

Test your knowledge with these retrieval practice exercises. These diagrams are rendered dynamically to ensure you can recognize UML notation in any context.

UML Class Diagram Flashcards

Quick review of UML Class Diagram notation and relationships.

Difficulty: Basic

What does the following symbol represent in a class diagram?

Detailed description

UML class diagram with 2 classes (Department, Professor). Department aggregates Professor.

Classes

  • Department — Attributes: none declared — Operations: none declared
  • Professor — Attributes: none declared — Operations: none declared

Relationships

  • Department aggregates Professor
Difficulty: Advanced

How do you denote a Static Method in UML Class Diagrams?

Difficulty: Intermediate

What is the difference between these two relationships?

Detailed description

UML class diagram with 4 classes (Building, Room, Library, Book). Building composes Room. Library aggregates Book.

Classes

  • Building — Attributes: none declared — Operations: none declared
  • Room — Attributes: none declared — Operations: none declared
  • Library — Attributes: none declared — Operations: none declared
  • Book — Attributes: none declared — Operations: none declared

Relationships

  • Building composes Room
  • Library aggregates Book
Difficulty: Intermediate

What is the difference between Generalization and Realization arrows?

Difficulty: Basic

What do the four visibility symbols mean in UML?

Difficulty: Basic

What does the multiplicity 1..* mean on an association?

Difficulty: Intermediate

What relationship is represented in the diagram below, and when is it used?

Detailed description

UML class diagram with 2 classes (Train, Event). Train depends on Event.

Classes

  • Train — Attributes: none declared — Operations: protected addStop(stop: Event): void
  • Event — Attributes: none declared — Operations: none declared

Relationships

  • Train depends on Event
Difficulty: Advanced

How do you indicate an abstract class in UML?

Difficulty: Advanced

List the class relationships from weakest to strongest.

Difficulty: Advanced

What does a navigable association () indicate?

UML Class Diagram Practice

Test your ability to read and interpret UML Class Diagrams.

Difficulty: Intermediate

Look at the following diagram. What is the relationship between Customer and Order?

Detailed description

UML class diagram with 2 classes (Customer, Order).

Classes

  • Customer — Attributes: private name: String; private email: String — Operations: none declared
  • Order — Attributes: private id: int; private date: Date — Operations: none declared
Correct Answer:
Difficulty: Intermediate

Which of the following members are private in the class Engine?

Detailed description

UML class diagram with 1 class (Engine).

Classes

  • Engine — Attributes: private serialNumber: String; protected type: String; public horsepower: int; private isRunning: boolean; package id: int — Operations: public start(); private resetInternal()
Correct Answers:
Difficulty: Basic

What type of relationship is shown here between Graphic and Circle?

Detailed description

UML class diagram with 1 class (Circle), 1 abstract class (Graphic). Circle extends Graphic.

Classes

  • Circle — Attributes: none declared — Operations: public draw()

Abstract classes

  • Graphic — Attributes: none declared — Operations: +draw() (abstract)

Relationships

  • Circle extends Graphic
Correct Answer:
Difficulty: Basic

Which of the following relationships is shown here?

Detailed description

UML class diagram with 2 classes (Car, Engine). Car composes Engine.

Classes

  • Car — Attributes: none declared — Operations: none declared
  • Engine — Attributes: none declared — Operations: none declared

Relationships

  • Car composes Engine
Correct Answer:
Difficulty: Intermediate

What type of relationship is shown between Payment and Processable?

Detailed description

UML class diagram with 1 class (Payment), 1 interface (Processable). Payment implements Processable.

Classes

  • Payment — Attributes: private amount: float — Operations: public process(): bool

Interfaces

  • Processable — Attributes: none declared — Operations: public process(): bool

Relationships

  • Payment implements Processable
Correct Answer:
Difficulty: Intermediate

What does the multiplicity 0..* on the Order side mean in this diagram?

Detailed description

UML class diagram with 2 classes (Customer, Order).

Classes

  • Customer — Attributes: private name: String — Operations: none declared
  • Order — Attributes: private date: Date — Operations: none declared
Correct Answer:
Difficulty: Advanced

Looking at this e-commerce diagram, which statements are correct? (Select all that apply.)

Detailed description

UML class diagram with 3 classes (Order, LineItem, Product), 1 interface (Billable). Order implements Billable.

Classes

  • Order — Attributes: private status: String — Operations: public calcTotal(): float
  • LineItem — Attributes: private quantity: int — Operations: none declared
  • Product — Attributes: private price: float — Operations: none declared

Interfaces

  • Billable — Attributes: none declared — Operations: public processPayment(): bool

Relationships

  • Order implements Billable
Correct Answers:
Difficulty: Basic

What does the # visibility modifier mean in UML?

Detailed description

UML class diagram with 1 class (Account).

Classes

  • Account — Attributes: private balance: float; protected accountType: String — Operations: public getBalance(): float
Correct Answer:
Difficulty: Intermediate

What type of relationship is shown here between Formatter and IOException?

Detailed description

UML class diagram with 2 classes (Formatter, IOException). Formatter depends on IOException.

Classes

  • Formatter — Attributes: none declared — Operations: public format(data: String): String
  • IOException — Attributes: none declared — Operations: none declared

Relationships

  • Formatter depends on IOException
Correct Answer:
Difficulty: Advanced

Given this Java code, what is the correct UML class diagram? java public class Student { Roster roster; public void storeRoster(Roster r) { roster = r; } }

Correct Answer:
Difficulty: Advanced

How is an abstract class indicated in UML?

Correct Answer:
Difficulty: Advanced

Which of the following Java code patterns would result in a dependency (dashed arrow) relationship in UML, rather than an association? (Select all that apply.)

Detailed description

UML class diagram with 3 classes (ReportGenerator, Logger, IOException). ReportGenerator depends on Logger. ReportGenerator depends on IOException.

Classes

  • ReportGenerator — Attributes: none declared — Operations: public generate(data: String): String
  • Logger — Attributes: none declared — Operations: none declared
  • IOException — Attributes: none declared — Operations: none declared

Relationships

  • ReportGenerator depends on Logger
  • ReportGenerator depends on IOException
Correct Answers:
Difficulty: Advanced

What does the arrowhead on this association mean?

Detailed description

UML class diagram with 2 classes (Employee, Boss). Employee references Boss.

Classes

  • Employee — Attributes: none declared — Operations: none declared
  • Boss — Attributes: none declared — Operations: none declared

Relationships

  • Employee references Boss
Correct Answer:
Difficulty: Advanced

When should you add navigability arrowheads to associations in a class diagram?

Detailed description

UML class diagram with 2 classes (Invoice, Customer). Invoice references Customer labeled "billedTo".

Classes

  • Invoice — Attributes: private total: float — Operations: none declared
  • Customer — Attributes: private name: String — Operations: none declared

Relationships

  • Invoice references Customer labeled "billedTo"
Correct Answer:

Pedagogical Tip: If you find these challenging, it’s a good sign! Effortful retrieval is exactly what builds durable mental models. Try coming back to these tomorrow to benefit from spacing and interleaving.

7. Interactive Tutorials

Master UML class diagrams by writing code that matches target diagrams in our interactive tutorials: