-
UML Diagram with SwiftCS/ETC 2022. 9. 30. 18:09
UML Class Diagram
UML 클래스 다이어그램은 객체 지향 시스템을 구성하고 시각화하는데 사용되는 그래픽적 표현이다. UML은 Unified Modeling Language의 약어로, UML의 클래스 다이어그램은 구조적인 다이어그램으로 다음의 시스템 요소들을 표현한다.
- 클래스
- 클래스의 속성
- 연산(메서드)
- 객체간의 관계
이름에서부터 알 수 있듯이 객체 지향 시스템의 핵심이 되는 객체를 생성하기 위한 '클래스'와 그들의 능력, 객체간의 관계를 시각적으로 표현한다.
Class란
Class가 무엇인지 모르고 클래스 다이어그램을 그릴 수는 없다.
클래스는 객체를 찍어낼 수 있는 틀이 된다. 클래스와 객체는 서로를 빼놓고 얘기할 수 없다. 객체 지향 디자인의 핵심은 객체가 아닌 클래스에 관한 것인데, 이는 클래스를 사용해서 객체를 생성하기 때문이다. 그래서 클래스는 객체가 어떤 특징을 갖고 어떤 연산을 할 수 있는지를 정의하지만, 객체는 스스로를 정의하지 않는다.
UML Class 표기법
클래스는 상태(attribute)와 행위(operation)을 캡슐화하는 개념을 나타낸다. 클래스 다이어그램은 클래스 이름, 클래스의 상태, 클래스의 행위를 표현해야 한다.
- 클래스 이름
- 필수적인 정보
- 맨 위에 기입한다.
- Attribute
attributeName : type
- 타입이 있다. 타입은 콜론 다음에 표시한다.
- 두 번째 위치에 기입한다.
- 각각의 attribute는 코드 상에서 멤버 변수가 된다.
- Operation
operation(inputSignature) : outputSignature
- 클래스가 제공하는 서비스다.
- 세 번째 위치에 기입한다.
- 리턴 타입의 메서는 메서드 signature(input과 output을 정의하는 것)의 콜론 다음에 기입한다.
- 각각의 Operation은 코드 상에서 메서드가 된다.
Class Visibility (접근 레벨)
Attribute, operation 이름 전에 붙는
+
,-
,#
심볼은 각각의 attribute와 operation의 가시성(접근 레벨)을 표시한다.+
: public-
: private#
: protected
Parameter Directionality
Operation(method)의 각각의 파라미터는
in
,out
,inout
으로 표시해서 호출하는 곳에 상대적인 방향을 나타낸다. 이런 방향은 파라미터 이름 전에 표시한다.in
: 호출자에 의해 전달됨out
: 호출자에 의해 전달되지 않지만, 결과로 나옴inout
: 호출자에 의해 전달되고, 연산에 의해 수정될 수 있드며 결과로 나온다.
클래스 간의 관계
UML은 단순히 클래스를 표현하기 위한 수단에서 그치지 않고 올바르게 사용했을 때 코드가 어떻게 구현되어야 하는지를 묘사하는 수단이 될 수 있다. 올바르게 해석되었을 때 구현된 코드는 디자이너의 의도를 완벽하게 반영할 수 있을 것이다.
클래스는 다른 클래스와의 관계가 없을 수도 있고, 하나 이상의 관계를 맺고 있을 수도 있다. 관계는 다음의 종류가 있다.
- Association
- Inheritance / Generalization
- Realization
- Dependency
- Aggregation
- Composition
특히 Aggregation과 Composition은 집합 관계에 포함된다.
- Association
- Generalization
- 집합 관계
- Aggregation
- Composition
- Dependency
- Realization
1. Association - 연관 관계
연관 관계는 UML 클래스 다이어그램의 클래스 간의 관계다. 딱히 특별한 것은 없고 관계라고만 생각하면 된다. 관계를 맺으면 클래스는 해당 연관 관계에서 어떤 역할을 수행한다.
두 클래스가 있고 두 클래스가 연관 관계를 맺고 있을 때 실선을 그어 연관 관계를 표시한다.
예를 들어 선생님 클래스와 학생 클래스가 있을 때 선생님이 학생을 가르치는 연관 관계를 코드로 표현하면 아래와 같이 될 것이다.
class Teacher { func teach(student: Student) {} } class Student { }
연관 관계를 표시할 때 추가로 다른 정보들도 같이 표시할 수 있다.
연관 관계 이름
두 클래스 사이의 연관관계를 나타내기 위해 사용한다.
Cardinality (다중성)
- 일대일
- 일대다
- 다대다
선에 아무런 숫자가 없으면 일대일 관계다.
방향
연관 관계는 방향성을 가질 수 있다.
- 양방향 : 실선. 두 클래스의 객체가 서로를 알고 있다.
- 단방향 : 화살표. 한쪽은 다른 클래스를 알지만 다른 클래스는 상대방을 모른다
연관 클래스
- 연관 관계에 추가할 속성이나 행위가 있을 때 사용한다. 연관 클래스는 두 클래스 사이에 위치시키고 점선을 사용해서 연결한다.
- 연관 클래스를 일반 클래스로 바꿔 다대다에서 일대다 연관 관계로 변환할 수 있다.
위 그림의 "대본" 클래스는 연관 클래스로 존재하지만, 이를 일반 클래스로 변환함으로써 교수 : 대본, 강의 : 대본을 일대다 관계로 변환했다.
2. Inheritance / Generalization - 상속, 일반화 관계
한 클래스가 다른 클래스를 포함하는 상위 개념일 때 존재한다. 즉 일반적인 클래스가 있고, 더 구체적인 클래스가 있다.
구체적인 클래스의 인스턴들은 일반적인 클래스의 간접적인 인스턴스가 된다. 일반적인 클래스는 구체적인 클래스의 공통 속성이나 연산을 제공하게 되고, 따라서 구체적인 클래스는 일반적인 클래스의 특징을 상속받는다.
- "is-a" 관계를 표현한다.
- 추상 클래스 이름은 이태릭체로 표시한다.
가령 아래와 같이
Animal
이라는 일반적인 클래스가 있고 이를 상속하는 구체적인Cat
클래스가 있다고 해보자.Cat
클래스는Animal
클래스의 특성을 사용할 수 있고, 추가로 자신만의 더 구체적인 특성을 가지고 있을 수 있다.class Animal { var name: String = "" func roar() {} } class Cat: Animal { var favoriteFish: String = "" }
클래스 다이어그램에서는 아래와 같이 빈 삼각형을 머리로 하는 화살표로 클래스간의 관계를 표시한다.
3. Realization - 실체화 관계
실체화 관계는 하나의 청사진과 이를 구현하는 객체가 맺는 관계다. 이 객체는 청사진 클래스를 실체화했다고 말한다. 즉 인터페이스와 구현 클래스 간의 관계라고 생각하면 된다.
가령 위와 같이
Owner
인터페이스가 있고, 얻고 해제하는 메서드를 명시하고 있다고 해보자.Person
과Corportation
클래스는 이런 메서드를 각각 다른 방법으로 구현할 수 있다.이를 코드로 나타내면 아래와 같다.
protocol Owner { func acquire() func dispose() } class Person: Owner { func acquire() { print("Person acquires") } func dispose() { print("Person disposes") } } class Corporation: Owner { func acquire() { print("Corporation acquires") } func dispose() { print("Corporation disposes") } }
4. Dependency - 의존 관계
한 클래스가 메서드에서 다른 클래스의 객체를 사용할 수 있는 관계를 의미한다. 메서드에서 사용한다는 것은 메서드의 파라미터로 사용될 때, 메서드 내부에서 사용되는 경우가 있을 수 있다. 만약 객체가 어디에도 저장되어 있지 않다면 의존 관계로 모델링되기도 한다.
이런 관계에서는 한 클래스의 정의를 바꾸면 다른 것에 영향을 끼친다. 예를 들어 클래스 A가 클래스 B에 의존할 때 클래스 B가 변한다면 클래스 A에도 영향이 있을 것이다. 하지만 그 역은 그렇지 않다.
의존 관계는 점선 화살표로 표시한다.
코드로는 아래와 같이 나타낼 수 있다.
class Person { func google(notebook: Notebook) { // do sth with notebook } } class Notebook {}
5. Aggregation - 집약 관계
한 객체가 다른 객체를 포함하는 관계를 나타낸다.
- "part of" 관계를 나타낸다.
- 한 객체가 다른 객체를 가지고 있기 때문에 일대다 관계를 가지고 있다.
- 각 클래스의 객체는 별개의 lifetime을 갖고 있다. 즉 다른 객체를 가진 객체가 메모리에서 없어져도 그 객체가 가지고 있던 객체는 사라지지 않는다.
- 다른 객체를 갖는 클래스 방향에 빈 마름모로 표시한다.
위 클래스 다이어그램을 코드로 표현하면 아래와 같이 될 것이다.
class Computer { var gpu: GPU init(gpu: GPU) { self.gpu = gpu } deinit { print("deinit computer") } } class GPU { deinit { print("deinit gpu") } }
6. Composition - 합성 관계
한 객체가 다른 객체에 속하는 관계를 나타낸다. 집약 관계와의 명확한 차이는 합성 관계는 부분 객체가 전체 객체가 메모리에서 해제될 때 같이 해제된다는 것이다. 즉 큰 객체의 생명이 끝나면 부분 객체의 생명도 끝나게 된다.
위 클래스 다이어그램을 코드로 표현하면 아래와 같이 될 것이다.
class Human { var liver = Liver() deinit { print("deinit human") } } class Liver { deinit { print("deinit liver") } } var human: Human? = Human() human = nil //deinit human //deinit liver
참고로 markdown을 사용해서도 uml diagram을 그릴 수 있다. Markdown으로 여러 uml diagram을 그리는 방법은 아래의 plantuml 문서를 참고하면 될 것 같다.
참조
반응형