Class Diagram Cheat Sheet

Get original Markdown
classDiagram
    class Vehicle
    class SUV
    class Rotatable { <<interface>> }
    class Motor
    Vehicle         <|--        SUV :          is a
(Generalization) Rotatable <|.. Motor : implements
(Realization)
classDiagram
    class Microphone
    class Speaker
    class Engine
    class Transmission
    Microphone      --          Speaker :      are associated
(Association) Engine <--> Transmission : are interdependent
(Bidirectional
Association)
classDiagram
    class TempSensor
    class TempGauge
    class Battery
    class Wiper
    TempSensor      <--         TempGauge :    refers to
(Directed
Association) Battery "1" <.. "*" Wiper : uses
(Temporary
Dependency)
classDiagram
    class Door
    class Window
    class Car
    class Tire
    Door       "1"  *-- "1..2"  Window :       composes
(Composition) Car "1" o-- "4..5" Tire : belongs to
(Aggregation)
Notation Coupling Term Reading Explanation
--|> High Generalization /
Specialization
is a A subclass inherits functionality from a superclass; conversely, a generalization relationship.
..|> Low Realization implements Implementation of an interface; some languages prefix interfaces with I, e.g., IMotor.
-- Mid Association are associated Some kind of relationship; direction is ambiguous, so not recommended.
<--> High Bidirectional
Association
are inter-
dependent
Bidirectional relationship; they reference each other; introduce an interface to achieve loose coupling.
--> Mid Directed
Association
refers to Unidirectional relationship; the referrer → the referent.
..> Low Temporary
Dependency
uses Temporary dependency; uses but does not own.
--* High Composition composes Strong ownership; when the whole is destroyed, the parts are also destroyed.
--o Mid Aggregation belongs to Weak ownership; parts remain if the whole is destroyed; relationship is ambiguous, so not recommended.

1. Generalization (is a)

Notation Coupling Term Reading Explanation
--|> High Generalization /
Specialization
is a A subclass inherits functionality from a superclass; conversely, a generalization relationship.
classDiagram
class Vehicle
class SUV
Vehicle <|-- SUV : is a
            
#include <iostream>
using namespace std;

// Generalization: SUV is a Vehicle
class Vehicle {
public:
    void move() {
        cout << "Vehicle moving" << endl;
    }
};

class SUV : public Vehicle {
public:
    void offRoad() {
        cout << "SUV off-roading" << endl;
    }
};

int main() {
    SUV suv;
    suv.move();     // inherited from Vehicle
    suv.offRoad();
    return 0;
}
// Generalization: SUV is a Vehicle
class Vehicle {
    move() {
        console.log("Vehicle moving");
    }
}

class SUV extends Vehicle {
    offRoad() {
        console.log("SUV off-roading");
    }
}

const suv = new SUV();
suv.move();     // inherited from Vehicle
suv.offRoad();
# Generalization: SUV is a Vehicle
class Vehicle:
    def move(self):
        print("Vehicle moving")

class SUV(Vehicle):
    def off_road(self):
        print("SUV off-roading")

suv = SUV()
suv.move()      # inherited from Vehicle
suv.off_road()

2. Realization (implements)

Notation Coupling Term Reading Explanation
..|> Low Realization implements Implementation of an interface; some languages prefix interfaces with I, e.g., IMotor.
classDiagram
class Rotatable { <<interface>> }
class Motor
Rotatable <|.. Motor : implements
            
#include <iostream>
using namespace std;

// Realization: Motor implements Rotatable interface
class Rotatable {
public:
    virtual void rotate() = 0;  // pure virtual function (interface)
    virtual ~Rotatable() {}
};

class Motor : public Rotatable {
public:
    void rotate() override {
        cout << "Motor rotating" << endl;
    }
};

int main() {
    Motor motor;
    motor.rotate();
    return 0;
}
// Realization: Motor implements Rotatable interface
class Rotatable {
    rotate() {
        throw new Error("Must implement rotate()");
    }
}

class Motor extends Rotatable {
    rotate() {
        console.log("Motor rotating");
    }
}

const motor = new Motor();
motor.rotate();
from abc import ABC, abstractmethod

# Realization: Motor implements Rotatable interface
class Rotatable(ABC):
    @abstractmethod
    def rotate(self):
        pass

class Motor(Rotatable):
    def rotate(self):
        print("Motor rotating")

motor = Motor()
motor.rotate()

3. Bidirectional Association (are interdependent)

Notation Coupling Term Reading Explanation
<--> High Bidirectional
Association
are inter-
dependent
Bidirectional relationship; they reference each other; introduce an interface to achieve loose coupling.
classDiagram
class Engine
class Transmission
Engine <--> Transmission : are interdependent
            
#include <iostream>
using namespace std;

class Transmission;

// Bidirectional Association: Engine and Transmission reference each other
class Engine {
private:
    Transmission* transmission;
public:
    Engine() : transmission(nullptr) {}
    void setTransmission(Transmission* t) { transmission = t; }
    void run() { cout << "Engine running" << endl; }
};

class Transmission {
private:
    Engine* engine;
public:
    Transmission() : engine(nullptr) {}
    void setEngine(Engine* e) { engine = e; }
    void shift() { cout << "Transmission shifting" << endl; }
};

int main() {
    Engine engine;
    Transmission transmission;
    
    engine.setTransmission(&transmission);
    transmission.setEngine(&engine);
    
    engine.run();
    transmission.shift();
    return 0;
}
// Bidirectional Association: Engine and Transmission reference each other
class Engine {
    constructor() {
        this.transmission = null;
    }
    
    setTransmission(transmission) {
        this.transmission = transmission;
    }
    
    run() {
        console.log("Engine running");
    }
}

class Transmission {
    constructor() {
        this.engine = null;
    }
    
    setEngine(engine) {
        this.engine = engine;
    }
    
    shift() {
        console.log("Transmission shifting");
    }
}

const engine = new Engine();
const transmission = new Transmission();

engine.setTransmission(transmission);
transmission.setEngine(engine);

engine.run();
transmission.shift();
# Bidirectional Association: Engine and Transmission reference each other
class Engine:
    def __init__(self):
        self.transmission = None
    
    def set_transmission(self, transmission):
        self.transmission = transmission
    
    def run(self):
        print("Engine running")

class Transmission:
    def __init__(self):
        self.engine = None
    
    def set_engine(self, engine):
        self.engine = engine
    
    def shift(self):
        print("Transmission shifting")

engine = Engine()
transmission = Transmission()

engine.set_transmission(transmission)
transmission.set_engine(engine)

engine.run()
transmission.shift()

4. Directed Association (refers to)

Notation Coupling Term Reading Explanation
--> Mid Directed
Association
refers to Unidirectional relationship; the referrer → the referent.
classDiagram
class TempSensor
class TempGauge
TempSensor <-- TempGauge : refers to
            
#include <iostream>
using namespace std;

// Directed Association: TempGauge refers to TempSensor
class TempSensor {
private:
    int temperature;
public:
    TempSensor() : temperature(25) {}
    int getTemperature() { return temperature; }
};

class TempGauge {
private:
    TempSensor* sensor;
public:
    TempGauge(TempSensor* s) : sensor(s) {}
    void display() {
        cout << "Temperature: " << sensor->getTemperature() << "C" << endl;
    }
};

int main() {
    TempSensor sensor;
    TempGauge gauge(&sensor);
    gauge.display();
    return 0;
}
// Directed Association: TempGauge refers to TempSensor
class TempSensor {
    constructor() {
        this.temperature = 25;
    }
    
    getTemperature() {
        return this.temperature;
    }
}

class TempGauge {
    constructor(sensor) {
        this.sensor = sensor;
    }
    
    display() {
        console.log(`Temperature: ${this.sensor.getTemperature()}C`);
    }
}

const sensor = new TempSensor();
const gauge = new TempGauge(sensor);
gauge.display();
# Directed Association: TempGauge refers to TempSensor
class TempSensor:
    def __init__(self):
        self.temperature = 25
    
    def get_temperature(self):
        return self.temperature

class TempGauge:
    def __init__(self, sensor):
        self.sensor = sensor
    
    def display(self):
        print(f"Temperature: {self.sensor.get_temperature()}C")

sensor = TempSensor()
gauge = TempGauge(sensor)
gauge.display()

5. Temporal Dependency (uses)

Notation Coupling Term Reading Explanation
..> Low Temporary
Dependency
uses Temporary dependency; uses but does not own.
classDiagram
class Battery
class Wiper
Battery "1" <.. "*" Wiper : uses
            
#include <iostream>
using namespace std;

// Temporal Dependency: Wiper uses Battery temporarily
class Battery {
public:
    void providePower() {
        cout << "Battery providing power" << endl;
    }
};

class Wiper {
public:
    void wipe(Battery& battery) {  // uses but does not own
        battery.providePower();
        cout << "Wiper wiping" << endl;
    }
};

int main() {
    Battery battery;
    Wiper wiper;
    wiper.wipe(battery);  // temporary usage
    return 0;
}
// Temporal Dependency: Wiper uses Battery temporarily
class Battery {
    providePower() {
        console.log("Battery providing power");
    }
}

class Wiper {
    wipe(battery) {  // uses but does not own
        battery.providePower();
        console.log("Wiper wiping");
    }
}

const battery = new Battery();
const wiper = new Wiper();
wiper.wipe(battery);  // temporary usage
# Temporal Dependency: Wiper uses Battery temporarily
class Battery:
    def provide_power(self):
        print("Battery providing power")

class Wiper:
    def wipe(self, battery):  # uses but does not own
        battery.provide_power()
        print("Wiper wiping")

battery = Battery()
wiper = Wiper()
wiper.wipe(battery)  # temporary usage

6. Composition (composes)

Notation Coupling Term Reading Explanation
--* High Composition composes Strong ownership; when the whole is destroyed, the parts are also destroyed.
classDiagram
class Door
class Window
Door "1" *-- "1..2" Window : composes
            
#include <iostream>
using namespace std;

// Composition: Door owns Window (strong ownership)
class Window {
public:
    Window() { cout << "Window created" << endl; }
    ~Window() { cout << "Window destroyed" << endl; }
    void open() { cout << "Window opening" << endl; }
};

class Door {
private:
    Window window;  // owned by Door
public:
    Door() { cout << "Door created" << endl; }
    ~Door() { cout << "Door destroyed" << endl; }
    void openWindow() { window.open(); }
};

int main() {
    {
        Door door;
        door.openWindow();
    }  // Door destroyed -> Window automatically destroyed
    cout << "End of program" << endl;
    return 0;
}
// Composition: Door owns Window (strong ownership)
class Window {
    constructor() {
        console.log("Window created");
    }
    
    open() {
        console.log("Window opening");
    }
}

class Door {
    constructor() {
        console.log("Door created");
        this.window = new Window();  // owned by Door
    }
    
    openWindow() {
        this.window.open();
    }
}

const door = new Door();
door.openWindow();
// When door is garbage collected, window is also collected
# Composition: Door owns Window (strong ownership)
class Window:
    def __init__(self):
        print("Window created")
    
    def __del__(self):
        print("Window destroyed")
    
    def open(self):
        print("Window opening")

class Door:
    def __init__(self):
        print("Door created")
        self.window = Window()  # owned by Door
    
    def __del__(self):
        print("Door destroyed")
    
    def open_window(self):
        self.window.open()

door = Door()
door.open_window()
del door  # Door destroyed -> Window automatically destroyed
print("End of program")