객체지향 모델링이란? - UML, Class Diagram
in CS on Design Pattern, Uml, Class-diagram
객체지향 모델링이란 무엇인가? UML, Class Diagram은 무엇인가?
모델링
모델은 관객들에게 디자이너가 보여주고 싶은 옷의 특징을 잘 보여줄 수 있어야 한다. 자동차 모델 같은 경우에는 모델만 보고도 바퀴가 몇 개이고 좌석이 얼마나 되는지 알 수 있어야 한다.
소프트웨어 개발에서 모델의 역할도 비슷하다. 모델의 역할은 크게 다음과 같다.
- 서로의 해석을 공유해 합의를 이루거나 해석의 타당성을 검토한다.
- 현재 시스템 / 앞으로 개발할 시스템의 원하는 모습을 가시화한다.
- 시스템의 구조와 행위를 명세할 수 있으며 시스템을 구축하는 틀을 제공한다.
모델은 추상화를 바탕으로 만들어져야 한다. 추상화는 대상에서 꼭 필요한 부분을 부각시킨다. 예를 들어 수강 시스템에서는 학생의 아침 식단은 전혀 중요하지 않으므로 시스템에서 제외될 수 있지만, 학번 같은 경우에는 매우 중요한 정보이므로 시스템에 포함되어야 한다.
UML
모델링을 하려면 시스템을 모델로 표현해주는 언어가 필요한데, 대표적으로 UML(Unified Modeling Language)가 있다.
UML은 요구 분석, 시스템 설계, 시스템 구현 등의 개발 과정에서 개발자 사이에 의사소통이 원활하게 이루어질 수 있도록 표준화된 통합 모델링 언어다.
UML 다이어그램의 종류는 아래와 같다.
분류 | 다이어그램 유형 | 목적 |
---|---|---|
구조 다이어그램(structure diagram) | 클래스 다이어그램(class diagram) | 시스템을 구성하는 클래스들 사이의 관계를 표현한다. |
객체 다이어그램(object diagram) | 객체 정보를 보여준다. | |
복합체 구조 다이어그램(composite structure diagram) | 복합구조의 클래스와 컴포넌트 내부 구조를 표현한다. | |
배치 다이어그램(deployment diagram) | 소프트웨어, 하드웨어, 네트워크를 포함한 실행 시스템의 물리 구조를 표현한다. | |
컴포넌트 다이어그램(component diagram) | 컴포넌트 구조 사이의 관계를 포함한다. | |
패키지 다이어그램(package diagram) | 클래스나 유즈 케이스 등을 포함한 여러 모델 요소들을 그룹화해 패키지를 구성하고 패키지들 사이의 관계를 표현한다. | |
행위 다이어그램(behavior diagram) | 활동 다이어그램(activity diagram) | 업무 처리 과정이나 연산이 수행되는 과정을 표현한다. |
상태 머신 다이어그램(state machine diagram) | 객체의 생명 주기를 표현한다. | |
유즈 케이스 다이어그램(use case diagram) | 사용자 관점에서 시스템 행위를 표현한다. | |
순차 다이어그램(sequence diagram) | 시간 흐름에 따른 객체 사이의 상호작용을 표현한다. | |
상호작용 개요 다이어그램(interaction overview diagram) | 여러 상호작용 다이어그램 사이의 제어 흐름을 표현한다. | |
통신 다이어그램(communication diagram) | 객체 사이의 관계를 중심으로 상호작용을 표현한다. | |
타이밍 다이어그램(timing diagram) | 객체 상태 변화와 시간 제약을 명시적으로 표현하다. |
위와 같이 다양한 다이어그램이 있는 이유는 다양한 관점에서 시스템을 모델링하기 위해서다.
클래스 다이어그램
클래스 다이어그램은 시간에 따라 변하지 않는 시스템의 정적인 면을 보여주는 대표적인 UML 구조 다이어그램이다.
클래스 다이어그램은 시스템을 구성하는 클래스와 그것들의 관계를 보여주기 때문에 주요 구성 요소는 클래스와 관계이다.
클래스
클래스란 동일한 속성과 행위를 수행하는 객체의 집합이다. / 공통의 속성과 책임을 찾는 객체들의 집합이자 실제 객체를 생성하는 설계도다.
고양이와 사자가 있다고 할 때 두 동물 모두 다 “울” 수 있다. 그리고 둘 다 꼬리를 가지고 있다. 이때 둘다 꼬리라는 것과 운다는 행위를 둘다 가지고 있으므로 고양이와 사자는 각각 하나의 객체가 될 수 있으며 고양이과 를 클래스로 볼 수 있는 것이다.
또 다른 관점은 클래스를 객체를 생성하는 설계도로 간주하는 것이다.
관계
클래스 하나만 존재하는 시스템은 없다. 클래스도 여러 개의 클래스가 모인 시스템이 훨씬 효율적이다. 객체지향에서는 클래스가 서로 관계를 맺어 기능을 수행한다.
알 UML에서 클래스는 아래와 같이 표현한다.
가장 윗부분에는 클래스 이름, 중간에는 속성, 마지막에는 연산(메서드)를 기술한다. 경우에 따라 속성 부분이나 연산 부분은 생략할 수 있다. 이 경우에는 생략된 부분을 위해 따로 선을 그리지 않아도 된다.
클래스의 속성과 연산을 기입할 때는 -
, +
와 같은 부호를 사용하는데, 이것은 속성과 연산의 가시화를 정의한 것이다. 가시화 정보는 외부에 속성과 연산을 어느 정도 공개하느냐에 따라 달라지고 아래는 접근 제어자를 UML에서 어떻게 나타내는지 표를 그린 것이다.
접근 제어자 | 표시 | 설명 |
---|---|---|
public | + | 어떤 클래스의 객체에서든 접근 가능 |
private | - | 이 클래스에서 생성된 객체들만 접근 가능 |
protected | # | 이 클래스와 동일 패키지에 있거나 상속 관계에 있는 하위 클래스의 객체들만 접근 가능 |
package | ~ | 동일 패키지에 있는 클래스의 객체들만 접근 가능 |
하지만 이런 가시화 정보를 항상 표시해야 하는 것은 아니다. 분석 단계에서는 가시화 정보보다 어떤 것을 속성으로 갖는지가, 설계 단계에서는 구체적인 타입과 가시화 정보가 중요할 수 있다. 따라서 속성과 연산 정보를 기입할 때 상황에 따라 생략해서 적을 수 있는 부분들이 있다. []
부분은 생략할 수 있는 부분을 의미한다.
표기방법 | |
---|---|
속성 | [+|-|#|~]이름:타입[다중성 정보][=초기값] |
연산 | [+|-|#|~]이름(인자1:타입1, …, 인자n:타입n) : 반환타입 |
보통 분석 단계의 클래스 다이어그램에서는 속성과 연산 항목에 타입 정보와 가시화 정보를 기술하지 않고, 설계 단계의 클래스에서는 바로 코드를 생성할 수 있게끔 구체적인 타입 정보와 가시화 정보를 기술한다. 아래는 UML에서 제공하는 클래스들 사이의 관계를 나타낸 표이다.
관계 | 설명 |
---|---|
연관 관계(association) | 클래스들이 개념상 서로 연결되었음을 나타낸다. 실선/화살표로 표시하고, 한 클래스가 다른 클래스에서 제공하는 기능을 사용하는 상황일 때 표시한다 |
일반화 관계(generalization) | 상속 관계. 한 클래스가 다른 클래스를 포함하는 상위 개념일 때 IS-A 관계라고 한다. 속이 빈 화살표로 표시한다. |
집합 관계(composition, aggregation) | 클래스 사이의 전체/부분 같은 관계를 나타낸다. |
의존 관계(dependency) | 한 클래스가 다른 클래스에서 제공하는 기능을 사용할 때를 나타낸다. 차이점은 두 클래스의 관계가 한 메서드를 실행하는 동안과 같은 아주 짧은 시간만 유지된다. 점섬 화살표로 나타낸다. |
실체화 관계(realization) | 책임들의 집합인 인터페이스와 이 책임들을 실제로 실현한 클래스들 사이의 관계를 나타낸다. 상속과 유사한 빈 삼각형을 사용하고 머리에 있는 실선 대신 점선을 사용해 나타낸다. |
1. 연관 관계
두 클래스가 연관 관계가 있을 때는 클래스 사이에 선을 그어 표시한다. 클래스 사이의 연관 관계가 명확할 경우에는 연관 관계 이름을 사용하지 않아도 된다.
한 클래스가 다른 클래스와 연관 관계를 가지면 각 클래스의 객체는 해당 연관 관계에서 특정 역할을 수행할 수 있는데 이는 클래스에 이어진 선 가까이에 적을 수 있다. 예를 들어 교수님 클래스와 학생 클래스가 있을 때 ‘상담한다’라는 연관 관계를 가진다고 해보자. 그러면 이때 교수님은 조언자, 학생은 학생의 역할을 수행하게 되는 것이다. 이런 관계는 양방향 연관 관계로 UML에서 두 클래스를 연결한 선에 화살표를 사용하지 않는다. 이는 두 클래스의 객체들이 서로의 존재를 인식한다는 의미이다.
또한 연관 관계를 나타내는 선에 아무런 숫자가 없으면 연관 관계가 1:1임을 나타내는 것이다. 위에서 든 예제에서, 교수님은 여러 명의 학생을 맡을 수 있는데, 이를 나타내기 위해 학생의 수를 선 근처에 표시한다. 이를 다중성(multiplicity)이라고 한다.
다중성을 나타내는 방법은 아래와 같다.
다중성 표기 | 의미 |
---|---|
1 | 딱 1. |
* | 0 이상 |
0..* | 0 이상 |
1..* | 1 이상 |
0..1 | 0 또는 1 |
2..5 | 2 이상 5 이하 |
1,2,6 | 1 또는 2 또는 6 |
1, 3..5 | 1 또는 3 또는 4 또는 5 |
연관 관계는 방향성을 가질 수 있다. 예를 들어 학생이 과목을 수강한다고 했을 때 화살표는 학생에서 나와 과목 쪽으로 들어가야 한다(과목을 화살표가 가리키고 있어야 한다.) 이 경우 학생은 자신이 수강하는 과목을 알지만 과목은 자신을 수강하는 학생들의 존재를 모른다는 것을 의미한다. 이렇게 방향성이 있는 연관 관계를 단방향 연관 관계라고 한다.
즉, 양방향 연관 관계는 서로의 존재를 안다는 의미이고, 단방향 연관 관계는 한 쪽은 알지만 다른 쪽은 상대방의 존재를 모른다는 의미이다.
일반적으로 다대다 연관 관계는 단방향 연관 관계가 아닌 양방향 연관 관계로 표현되는 것이 적절하다. 하지만 다대다 관계는 자연스럽게 양방향 연관 관계가 되므로 구현하기 복잡한데, 이 관계를 일대다 단방향 연관 관계로 변환해 구현한다.
추가로 학생과 수강 과목 을 연관 관계로 표시한다고 할 때, 성적 정보는 어디에 포함될까? 성적 정보는 ‘학생’이 ‘과목’을 수강해야 생기는 것이므로 학생이나 과목 중 오로지 하나에만 포함될 수 없다. 따라서 성적 정보는 클래스의 속성이 아닌 ‘수강하다’라는 연관 관계의 속성으로 다뤄야 한다. 이때 연관 클래스를 사용하는 것이다.
연관 클래스는 연관 관계에 추가할 속성이나 행위가 있을 때 사용하고, 아래 그림과 같이 표시한다.
이 예에서 1. 학생 2. 과목 3. 성적 클래스를 생성할 수 있다. 성적 객체는 하생과 과목에 대한 정보를 모두 담고 있어야 한다. 학생은 여러 개의 성적을 받을 수 있고, 한 과목에서도 여러 가지 성적이 산출된다. 따라서 학생과 성적의 관계, 과목과 성적의 관계는 일대다 이다. 이것을 기반으로 위의 다이어그램을 수정하면 아래와 같다.
한 학생이 한 과목을 재수강해서 성적 정보를 여러개 가질 수 있는데, 성적 클래스 이름 아랫부분에 연관관계의 이력(history)를 쓰면 된다.
연관 관계는 재귀적일 수 있다. 재귀적 연관 관계란 동일한 클래스에 속한 객체들 사이의 관계다. 예를 들어 직원에 관리자와 사원 클래스가 있다 해보자. a가 b를 관리하는 관리자이면 a는 관리자, b는 사원이 된다. 하지만 b도 c를 관리하는 관리자라면 b는 관리자이면서 사원이 되는 것이다. 이렇게 두 클래스에 속하는 모순이 발생하고, 이렇게 두 개의 클래스로 나눠서 관리하면 시스템이 바뀔 때 유연성이 부족할 수 있으므로 역할은 클래스로 웬만해서 만들지 않는 것이 좋다. 그래서 아래와 같이 재귀적인 연관 관계가 등장했다.
하지만 a가 b를 관리하고 b가 c를 관리하고 c가 a를 관리하는 상황처럼 관계의 루프가 발생하는 경우에 문제가 발생하는데, 이런 상황을 배제하기 위해 연관 관계에 아래와 같이 제약을 설정한다.
제약은 {}
안에 정해진 제약, 문장을 자유롭게 쓸 수 있고, 클래스나 연관 관계를 포함한 UML 모델 요소가 따라야 하는 규칙을 붙여줄 때 사용한다. 위 그림에서 계층
은 객체 사이에 상하 관계가 존재하고 사이클이 존재하지 않는다는 의미이다.
2. 일반화 관계
한 클래스가 다른 클래스를 포함하는 상위 개념일 때 두 클래스 사이에는 일반화 관계가 존재한다. 이를 객체지향 개념에서는 ‘상속 관계’라고 하고, ‘is a kind of 관계’랑 같은 말이다.
상위 클래스를 부모 클래스, 하위 클래스를 자식 클래스라고 한다. UML에서 일반화 관계는 화살표의 끝에 빈삼각형 표시를 해 표시한다. 삼각형 표시가 있는 쪽이 부모 클래스, 반대쪽은 자식 클래스다.
자식 클래스들에는 공통 되는 연산들이 있을 수 있는데, 이때 부모 클래스에 구현하지 않은 빈 껍데기만 있는 연산을 선언한다. 이를 추상 메서드라고 한다. 빈 껍데기만 만들어 놓는 이유는 이를 자식 클래스에서 상속해서 구현을 모두 다르게 할 수 있기 때문이다. 이처럼 추상 메서드를 하나 이상 가지는 클래스를 추상 클래스라고 하고, 다른 일반 클래스와는 다르게 객체를 생성할 수 없다. UML에서는 추상클래스와 메서드를 이탤릭체로 써서 구분하거나 스테리오 타입(‘«’,’»’ 안에 이름 넣어 표시)으로 표시한다.
3. 집합 관계
집합 관계는 UML 연관 관계의 특별 경우로 전체와 부분의 관계를 명확하게 명시하고자 할 때 사용한다. 1. 집약과 2. 합성 두 종류의 집합 관계가 존재한다.
- 집약 관계 집약 관계는 한 객체가 다른 객체를 포함하는 것을 나타낸다. 이때 전체 객체의 라이프타임과 부분 객체의 라이프타임은 독립적이라 전체 객체가 메모리에서 사라진다 해도 부분 객체는 사라지지 않는다. 전체를 가리키는 클래스 방향에 빈 마름모로 표시한다.
- 합성 관계 합성 관계는 부분 객체가 전체 객체에 속하는 관계다. 전체를 가리키는 클래스 방향에 채워진 마름모료 표시한다. 전체 객체가 사라지면 부분 객체도 사라진다.
아래의 코드를 비교해보자.
// Computer객체가 사라지면 메인보드, CPU 객체가 사라진다.
public class Computer {
private MainBoard mb;
private CPU c;
public Computer() {
this.mb = new MainBoard();
this.c = new CPU();
}
}
// Computer 객체가 사라져도 메인보드, CPU 객체는 남아있다. 외부에서 참조만 받아 사용했기 떄문.
public class Computer {
private MainBoard mb;
private CPU c;
public Computer(MainBoard mb, CPU c) {
this.mb = mb;
this.c = c;
}
}
4. 의존 관계
한 클래스가 다른 클래스를 사용하는 경우는 3가지가 있다.
- 클래스의 속성에서 참조할 때
- 연산의 인자로 사용도리 때
- 메서드 내부의 지역객체로 참조될 때
사람-차 의 관계를 봤을 때, 보통 한 사람은 자차를 갖고 있을 때 오랫동안 그 차를 이용할 것이다. 이럴 경우 오랜 기간 관계를 가진다고 할 수 있는데, 자동차-주유기 관계를 보면 다르다. 주유할 때 특정 주유기만 계속 사용할 수 있다는 보장이 없으며, 이용하는 주유기가 매번 달라질 수 있다. 이를 객체지향 프로그램에서는 사용되는 주유기를 인자나 지역 객체로 생성해 구현할 것이다.
연관 관계는 오랜 시간 같이할 객체와의 관계, 의존 관계는 짧은 시간 동안 이용하는 관계다.
5. 인터페이스와 실체화 관계
인터페이스란 책임이다. 실제로 책임을 수행하는 객체는 아니며, 이를 실현하는 클래스에서 책임을 수행한다. UML에서는 화살표를 빈 삼각형을 가진 끝과 함께 점선으로 표시한다.