low-level-design3 min read

Class Diagrams UML Tutorial from Scratch (2026)

Class Diagrams UML Tutorial from Scratch (2026)

Published:  |  Category: Low Level Design  |  Reading time: ~15 min
Class Diagrams UML Tutorial from Scratch (2026)

Class diagrams are the backbone of object-oriented design, providing a static view of the system entities, their attributes, methods, and relationships. They translate directly into code structures such as classes, interfaces, and enumerations, making them indispensable for low-level design documentation.

In this tutorial you will learn to model classes, interpret multiplicity, distinguish aggregation from composition, understand inheritance notations, and apply visibility modifiers. By the end, you will be able to read and create class diagrams that communicate design intent clearly.

Classes, Attributes, and Methods

A class is depicted as a rectangle divided into three compartments: the top holds the class name, the middle lists attributes with their types, and the bottom lists operations with their parameters and return types. Visibility is indicated by + (public), - (private), # (protected), and ~ (package-private).

// PlantUML - class with visibility and types
' @startuml
class User {
  - id: UUID
  - email: String
  - passwordHash: String
  + User(email: String, password: String)
  + getId(): UUID
  + getEmail(): String
  + setEmail(email: String): void
  + isPasswordValid(password: String): Boolean
}
' @enduml

Relationships and Multiplicity

Relationships between classes include association (solid line), inheritance (empty triangle), realization (dashed empty triangle), dependency (dashed arrow), and aggregation/composition (diamond). Multiplicity defines cardinality constraints such as 1, 0..*, 1..*, or 0..1 on relationship endpoints.

class Order {
  constructor() {
    this.items = [];
    this.customer = null;
  }

  addItem(product, quantity) {
    this.items.push(new OrderItem(product, quantity));
  }

  assignCustomer(customer) {
    this.customer = customer;
  }
}

class OrderItem {
  constructor(product, quantity) {
    this.product = product;
    this.quantity = quantity;
    this.price = product.price * quantity;
  }
}

class Customer {
  constructor(name) {
    this.name = name;
    this.orders = [];
  }
}

Aggregation vs. Composition and Inheritance

Aggregation (hollow diamond) represents a whole-part relationship where the part can exist independently of the whole, e.g., a Department contains Employees who can move to another department. Composition (filled diamond) implies stronger ownership where the part lifecycle depends on the whole, e.g., a House contains Rooms that are destroyed when the house is demolished.

class Department {
  constructor(name) {
    this.name = name;
    this.employees = [];
  }

  addEmployee(emp) {
    this.employees.push(emp);
    emp.department = this;
  }
}

class Employee {
  constructor(name) {
    this.name = name;
    this.department = null;
  }
}

class House {
  constructor(address) {
    this.address = address;
    this.rooms = [new Room("Living Room"), new Room("Bedroom")];
  }
}

class Room {
  constructor(name) {
    this.name = name;
  }
}

class Animal {
  speak() { throw new Error("Subclass must implement"); }
}

class Dog extends Animal {
  speak() { return "Woof"; }
}

class Cat extends Animal {
  speak() { return "Meow"; }
}

Frequently Asked Questions

What is the difference between association and dependency?

Association is a structural relationship that implies a long-term connection between classes, often stored as a field. Dependency is a weaker, transient relationship where one class temporarily uses another, such as a method parameter or local variable.

How do I decide between aggregation and composition?

Use composition when the child cannot exist without the parent (lifecycle dependency) and aggregation when the child can be shared or exist independently. If unsure, prefer composition for stronger consistency guarantees.

What does a dashed arrow with an open triangle mean?

It represents realization, typically used when a class implements an interface. The dashed line connects the implementing class to the interface, with the triangle pointing at the interface.

Can I model abstract classes and interfaces in class diagrams?

Yes, abstract class names are written in italics or decorated with {abstract}. Interface names use the <> stereotype above the name, and their operations are linked via realization relationships.

Originally published on Ayodhyyya. Last updated June 1, 2026.