code documentation - software development - UML diagrams -

7 UML Class Diagram Examples with Relationships Explained

Study seven practical UML class diagram examples for libraries, shops, banks, hospitals, rentals, schools, and issue trackers, with relationship notes.

Written by DocuWriter.ai Reviewed by DocuWriter Editorial Team on September 7, 2026

These seven UML class diagram examples show classes, attributes, operations, multiplicity, inheritance, composition, and dependencies in systems developers recognize. Each example includes a PlantUML definition so you can render it, change it, and see how the model reacts.

The diagrams are intentionally small. A useful class diagram should answer a design question; it does not need to reproduce every class in the codebase.

How to read the UML notation

UML class diagram notation and relationships

A UML class normally has three compartments: its name, attributes, and operations. The common visibility markers are + for public, - for private, # for protected, and ~ for package visibility.

Relationships carry most of the meaning:

RelationshipPlantUMLRead it as
Association--Objects know about or work with each other
Inheritance`<—`
Interface realization`<..`
Composition*--The part belongs to the whole and shares its lifecycle
Aggregationo--The whole groups parts that can exist independently
Dependency..>One element uses another without owning it

Multiplicity such as 1, 0..1, and 0..* states how many instances can participate. The OMG UML 2.5.1 specification is the normative reference; the examples below use the practical notation documented by PlantUML.

1. Library management UML class diagram example

A library model needs to separate a catalog title from a physical copy. Otherwise, a single Book object ends up carrying both shared metadata and copy-specific state such as a barcode or loan status.

@startuml
class Book {
  +isbn: String
  +title: String
}

class BookCopy {
  +barcode: String
  +status: CopyStatus
}

class Member {
  +memberId: String
  +borrow(copy: BookCopy)
}

class Loan {
  +borrowedAt: Date
  +dueAt: Date
  +returnedAt: Date?
}

Book "1" *-- "1..*" BookCopy : editions
Member "1" -- "0..*" Loan
BookCopy "1" -- "0..*" Loan
@enduml

Book composes one or more BookCopy records. A Loan connects one member to one copy and stores facts about that borrowing event. Keeping Loan as a class makes due dates, returns, and renewals explicit instead of hiding them on an association line.

Question this diagram answers: Can two members borrow the same physical copy at once? The model permits many historical loans, so the application must also enforce that no active loan already exists for the copy.

2. E-commerce UML class diagram example

E-commerce UML class diagram relationships

This example separates products from order lines. Prices change over time, so an order line stores the price charged at checkout rather than reading the current product price whenever an old order is viewed.

@startuml
class Customer {
  +customerId: UUID
  +email: String
}

class Order {
  +orderNumber: String
  +placedAt: DateTime
  +status: OrderStatus
  +total(): Money
}

class OrderLine {
  +quantity: int
  +unitPrice: Money
}

class Product {
  +sku: String
  +name: String
  +currentPrice: Money
}

Customer "1" -- "0..*" Order : places
Order "1" *-- "1..*" OrderLine
OrderLine "0..*" --> "1" Product
@enduml

Composition fits OrderLine because a line has no meaning outside its order. Product is associated rather than composed: deleting or archiving a product must not erase order history.

Question this diagram answers: Where does the historical sale price live? It is captured by OrderLine.unitPrice.

3. Bank account UML class diagram example

Bank account UML class diagram example

Banking examples often overuse inheritance. Here, inheritance is limited to account types that genuinely share an account contract while applying different rules.

@startuml
abstract class Account {
  +accountNumber: String
  +balance: Money
  +withdraw(amount: Money)
}

class CheckingAccount {
  +overdraftLimit: Money
}

class SavingsAccount {
  +interestRate: Decimal
}

class AccountHolder {
  +customerId: String
  +legalName: String
}

class Transaction {
  +transactionId: UUID
  +amount: Money
  +postedAt: DateTime
}

Account <|-- CheckingAccount
Account <|-- SavingsAccount
AccountHolder "1..*" -- "1..*" Account : owns
Account "1" *-- "0..*" Transaction
@enduml

The many-to-many ownership allows joint accounts and customers with several accounts. Whether transactions should be modeled as composition depends on retention rules. If transactions must survive account closure independently, use an association and show the archive boundary in a larger model.

Question this diagram answers: Which behavior belongs to every account, and which rules vary by account type?

4. Hospital appointment UML class diagram example

This model focuses on scheduling rather than trying to represent an entire clinical system.

@startuml
class Patient {
  +patientId: String
  +dateOfBirth: Date
}

class Clinician {
  +clinicianId: String
  +specialty: String
}

class Appointment {
  +startsAt: DateTime
  +durationMinutes: int
  +status: AppointmentStatus
  +cancel(reason: String)
}

class ConsultationNote {
  +createdAt: DateTime
  +body: Text
}

Patient "1" -- "0..*" Appointment
Clinician "1" -- "0..*" Appointment
Appointment "1" *-- "0..1" ConsultationNote
@enduml

Appointment is not a line drawn directly between Patient and Clinician; it has its own lifecycle and data. The note is optional because an appointment may be scheduled or cancelled without a consultation.

Question this diagram answers: Where are appointment status and cancellation details stored?

5. Vehicle rental UML class diagram example

In a rental system, a vehicle category and a physical vehicle are different concepts. A customer may reserve a category before the company assigns a particular vehicle.

@startuml
class Customer {
  +customerId: UUID
  +licenceNumber: String
}

class VehicleCategory {
  +code: String
  +dailyRate: Money
}

class Vehicle {
  +vin: String
  +registration: String
  +odometerKm: int
}

class Reservation {
  +startsOn: Date
  +endsOn: Date
  +status: ReservationStatus
}

VehicleCategory "1" o-- "0..*" Vehicle
Customer "1" -- "0..*" Reservation
Reservation "0..*" --> "1" VehicleCategory : requests
Reservation "0..*" --> "0..1" Vehicle : assigned
@enduml

Aggregation shows that vehicles are grouped by category but remain independent assets. The optional assignment captures a real scheduling state: a valid reservation can exist before a specific vehicle is chosen.

Question this diagram answers: Can a reservation be confirmed before a vehicle is assigned? Yes; the multiplicity is 0..1.

6. Student information UML class diagram example

Enrollment is another case where an association deserves its own class. A student-course link needs a term, status, and grade.

@startuml
class Student {
  +studentId: String
  +name: String
}

class Course {
  +courseCode: String
  +title: String
  +credits: int
}

class CourseOffering {
  +term: String
  +capacity: int
}

class Enrollment {
  +enrolledAt: DateTime
  +status: EnrollmentStatus
  +grade: String?
}

Course "1" -- "0..*" CourseOffering
Student "1" -- "0..*" Enrollment
CourseOffering "1" -- "0..*" Enrollment
@enduml

Course describes the catalog entry; CourseOffering represents one scheduled occurrence. A student enrolls in an offering, not in the timeless catalog record.

Question this diagram answers: Where does a grade belong when a student repeats the same course? On the enrollment for a specific offering.

7. Issue tracker UML class diagram example

The final UML class diagram example shows interface realization and a dependency in addition to associations.

@startuml
interface NotificationChannel {
  +send(recipient: User, issue: Issue)
}

class EmailChannel
class SlackChannel
class User {
  +userId: UUID
  +email: String
}
class Project {
  +projectKey: String
}
class Issue {
  +number: int
  +title: String
  +status: IssueStatus
  +assignTo(user: User)
}
class AssignmentService {
  +assign(issue: Issue, user: User)
}

NotificationChannel <|.. EmailChannel
NotificationChannel <|.. SlackChannel
Project "1" *-- "0..*" Issue
Issue "0..*" --> "0..1" User : assignee
AssignmentService ..> NotificationChannel : notifies through
@enduml

The service depends on the NotificationChannel abstraction, so email and Slack delivery can change without changing assignment rules. The assignee is optional because a newly created issue may sit in a backlog unassigned.

Question this diagram answers: Which part owns notification delivery, and can that delivery mechanism be replaced?

What these UML class diagram examples leave out

A class diagram shows static structure. It does not show the order of calls, timing, deployment topology, or every business rule. Add a sequence diagram when message order matters, an activity diagram for workflow decisions, or a deployment diagram for runtime infrastructure.

Also avoid treating a diagram as proof that the implementation follows the model. If the diagram comes from a design discussion, compare it with the source code. If it is generated from code, review names, inferred relationships, omitted runtime behavior, and external dependencies.

A checklist for your own class diagram

Before sharing a diagram, check that:

  • every class supports the question the diagram is meant to answer;
  • relationship direction and multiplicity are explicit where they matter;
  • composition is reserved for shared lifecycles, not used as a decorative strong line;
  • association classes hold data that belongs to a relationship;
  • interfaces describe replaceable behavior;
  • names match the terms used by the code and product;
  • the diagram has a version or source reference so readers know when it was accurate.

These UML class diagram examples are starting models, not drop-in domain designs. Change the constraints to match the system you are building.

For more tooling options, compare our free UML diagram makers or read about code-to-UML diagram generators. DocuWriter can generate diagrams alongside architecture, modules, services, classes, functions, dependencies, APIs, and other codebase documentation, then organize the output in Spaces for review and maintenance.