클래스 다이어그램

 

클래스와 클래스간의 관계를 보여준다.

클래스에 대한 모든 정보를 작성하는 것은 아니고 클래스의 구성요소인 멤버속성들과 멤버함수들에 대해 작성한다.

함수를 어떻게 작성해야할지 등을 자세히 작성하는건 아니다.

 

Use Case의 명사가 클래스가 되며 동사들은 메서드가 될 수 있다.

 

 

 

클래스 다이어그램의 구조

 

 

1) 구성

클래스 다이어그램의 하나의 클래스는 아래의 3가지 요소로 이루어져 있다.

- 클래스 이름

- 속성(멤버변수)

- 오퍼레이션(멤버함수)

 

2) 의미

멤버들 앞의 기호는 공개수준이다.

+ : public

- : private

# : protected

~ : package/internal

 

()가 붙으면 오퍼레이션으로 취급되고 안붙으면 속성로 취급된다.

 

3) 작성법

속성의 작성순서는 보통 아래의 형태로 한다.

가시성 이름 : 타입 = 기본값

예를들어
+name : String = mike

위처럼 표시하면 public String name필드의 default값은 mike로 한다 라는 뜻이다.

 

 

오퍼레이션의 작성 순서는 보통 아래의 형태로 한다.

가시성 이름(매개변수 목록) : 리턴타입

+func(arr : int) : int

위처럼 표시하면 int func(int arr) {} 와 같은 형식이다.

 

오퍼레이션의 밑줄은 static 메서드를 의미한다.

오퍼레이션의 기울임 글꼴은 abstract 메서드를 의미한다.

클래스 이름이 기울임체인것도 추상클래스를 의미한다.

 

 

 

클래스간의 관계

 

 

클래스 다이어그램에서 클래스간의 다양한 관계 형태가 있다.

주로 선만 표현할때가 많고 연관방향/연관이름/역할명 등은 필요할때만 쓴다.

역할명은 보통 클래스에 있는 필드(프로퍼티)에 있는 내용을 역할명으로 사용함, 위에선 lineItems가 Order의 필드고 lineItems의 타입이 OrderLine

 

1) Association(연관)

두 클래스 사이의 관계를 보여주며 방향성을 나타내지는 않는다.

양방향으로 정보 전달시에 사용한다.

객체간의 의존성을 나타낸다. 다만 객체 간의 수명 주기의 종속성은 없다.

 

화살표를 양쪽 다 붙인것과 양쪽 다 안붙인것은 의미가 같음. 둘 다 양방향 탐색을 의미

classDiagram
    class Employer {
    }
    class Employee {
    }

    Employer--Employee

    class Animal {
    }
    class Car {
    }

    Animal..Car

 

2) Navigable Association(방향성)

위의 Association에 화살표가 있는 경우이다.

어떤 클래스가 다른 클래스의 인스턴스를 탐색할 수 있는 관계를 나타낸다.

 

또한 HAS-A 상황에서도 사용되는것 같음

 

고용주가 피고용인의 정보를 탐색할 수 있는 관계  
Employer -> Employee라면 Employer가 Employee의 public속성이나 operation에 접근 가능한 상황을 의미  

classDiagram
    class Employer {
    }
    class Employee {
    }

    Employer-->Employee

 

3) Inheritance(상속)

Inheritance(상속), Generalization(일반화)에 사용

클래스가 다른 클래스를 상속받을때 사용한다.

is-A 상황에 사용

classDiagram
    class Animal {
    }
    class Cat {
    }

    Animal<|--Cat

 

4) Realization / Implementation(실현 관계)

추상클래스 또는 인터페이스와 클래스의 관계

클래스가 상속을 받고 순수가상함수를 실제로 구현할 때 사용

classDiagram
    class Interface {
        virtual operation()
    }
    class Concrete {
        operation()
    }

    Interface<|..Concrete
    <<Abstract>> Interface

 

5) Dependency(의존 관계)

클래스가 다른 클래스 객체를 매개변수로 받거나, 다른 클래스의 멤버 변수를 참조하는 경우

즉 의존성이 발생하는 경우

의존관계가 발생하는 함수를 수행중일때만 관계가 있고 해당 함수가 끝나면 관계가 사라짐

 

어댑터가 생각나는상황

class ClassA
{
public:
	void doSomething() { cout << "ClassA is doing something."; }
};

class ClassB
{
public:
	void performAction(ClassA* a) { a->doSomething(); }
};

위와 같은 코드가 있다면 ClassA는 독립적으로 존재하지만 ClassB는 ClassA의 객체를 매개변수로 받아서 해당 객체를 사용하므로 ClassA에게 의존성이 있음

다만 performAction함수가 끝나면 a객체는 소멸되고 ClassA와 ClassB의 관계도 사라지게 되므로 ClassB는 ClassA의 정보를 볼 수 없음

classDiagram
    class ClassA {
        doSomething()
    }
    class ClassB {
        performAction(ClassA)
    }

    ClassA<..ClassB

 

6) Aggregation(집합)

한 객체가 다른 객체를 포함하되 포함된 객체의 수명 주기는 독립적인 경우

만약 객체가 사라질때 포함된 객체도 같이 사라진다면 아래의 Composition(합성)관계가 된다.

 

HAS-A 관계인데 Navigable Association과의 차이점은 다중성을 통해 표현됨

예를들어 Company가 여러명의 Employee를 가지고 있을 수 있음

 

아래 예시처럼 Company has Employee이지만 Company객체가 소멸된다고 해서 Employee객체도 소멸되는 것은 아닌 상황에 사용

#include <bits/stdc++.h>
using namespace std;

class Employee { };

class Company
{
private:
	string name;
	vector<Employee*> employees;
    
public:
	void addEmployee(Employee* employee) { employees.push_back(employee); }
};

int main()
{
	Employee* emp1 = new Employee("emp1");
	Employee* emp2 = new Employee("emp2");
	Company* com1 = new Company("com1");

	com1->addEmployee(emp1);
	com1->addEmployee(emp2);

	delete com1;

	// 여전히 Employee는 살아있음

	return 0;
}

즉 HAS-A이면서 다중성을 갖고 수명주기는 독립적인 경우

classDiagram
    class Company {
        vector~Employee~ employees
        addEmployee(Employee)
    }
    class Employee {
    }

    Company o-- Employee

 

7) Composition(합성)

위에 있는 Aggregation(집합)의 특별한 형태로 더 강한 종속성을 표현

한 객체의 수명주기가 다른 객체에 의해 관리되는 경우

 

스마트포인터가 생각나는 상황

 

아래처럼 어느 클래스의 객체가 특정 클래스에서만 사용되는 경우

컴퓨터 객체가 소멸되면 cpu객체도 같이 소멸되게 됨

#include <iostream>
using namespace std;

class CPU
{
public:
	void start() { cout << "starting" << '\n'; }
};

class Computer
{
private:
	CPU cpu;
public:
	void booting()
	{
		cpu.start();
		cout << "booting" << endl;
	}
};

int main()
{
	Computer* computer = new Computer();
	computer->booting();

	delete computer;

	return 0;
}
classDiagram
    class CPU {
    }
    class Computer {
        CPU cpu
    }

    Computer *-- CPU

 

 

 

다중성

 

다중성(multiplicity / cardinality on relations)

DB ERD에서 카디널리티를 생각하면 된다.

 

클래스의 각 인스턴스 간의 관계에서 객체의 갯수나 범위를 표현

 

예를들어 고객 1명이 여러개의 티켓을 가지고 있다, 학생 한명이 한개이상의 코스를 가지고 있다라면 아래처럼 표현한다.

classDiagram
    Customer "1" --> "*" Ticket
    Student "1" --> "1..*" Course

 

 

 

 

 

 

※ 참고 문헌

https://bloodstrawberry.tistory.com/1384

https://bloodstrawberry.tistory.com/1361

https://mermaid.js.org/syntax/classDiagram.html

https://youtu.be/HG0dwNnTsII?si=Y7XDNUv9s6jeuFkh