모듈화를 함에 있어서 UML이 무엇인지, UML을 이용해 클래스 다이어그램을 작성하는 방법을 공부하기 위한 포스팅이다.

  • UML(Unified Modeling Language)
    • 시스템을 모델로 표현해주는 대표적인 모델링 언어.
  • UML 다이어그램의 종류
    1. 구조 다이어그램
      • 클래스 다이어그램, 객체 다이어그램, 복합체 구조 다이어그램, 배치 다이어그램, 컴포넌트 다이어그램, 패키지 다이어그램.
    2. 행위 다이어그램
      • 활동 다이어그램, 상태 머신 다이어그램, 유즈 케이스 다이어그램, 상호작용 다이어그램.
  • UML 작성 도구

클래스 다이어그램이란

  • 시간에 따라 변하지 않는 시스템의 정적인 면을 보여주는 대표적인 UML 구조 다이어그램이다.
  • 목적 : 시스템을 구성하는 클래스들 사이의 관계를 표현한다.

클래스

  • 클래스란
    1. 동일한 속성과 행위를 정의한 객체의 집합.
    2. 객체를 생성하는 설계도.
  • 클래스는 변화의 기본 단위
    • 디자인 패턴을 제대로 이해하려면 만들진 프로그램을 흔들어보고 어떤 것이 변화되는지를 잘 살펴봐야 한다.
  • UML 클래스의 표현은 아래 그림과 같다.
    • 가장 위 : 클래스 이름
    • 중간 : 속성(클래스의 특징, 변수)
    • 마지막 : 연산(클래스가 수행하는 책임, 메소드)
    • 경우에 따라 속성과 연산 부분은 생략 가능.
  • 속성과 연산의 가시화를 정의
    • UML에서는 접근 제어자를 사용해 나타낼 수 있다.
  • 분석 단계와 설계 단계에서의 클래스 다이어그램은 아래와 같다.
    • 분석 단계는 조금 더 간략하게 표시한다.
    • 설계 단계는 보다 더 세밀하게 작성한다.

관계

UML에서 제공하는 클래스들 사이의 관계는 아래의 표와 같다.
표를 먼저 보고 각 관계의 의미에 대해서 알아보도록 하자.

서로 의미있는 클래스들의 관계에는 크게 4가지 종류가 있다.
일반적인 의미의 연결 관계인 연관(association) 관계, 전체와 부분을 나타내는 집합(aggregation) 관계, 다른 클래스의 속성을 물려받는 상속(inheritance) 관계, 그리고 한 클래스가 다른 클래스에 영향을 미치는 의존(dependency) 관계가 있다.

연관 관계와 의존 관계를 구분 짓는 가장 큰 기준은
참조하는 클래스 인스턴스의 참조를 계속 유지하고 있느냐, 아니냐이다.
아래의 코드에서 확인할 수 있다.

  • 연관 관계 : 참조를 유지한다.
  • 의존 관계 : 참조를 짧게 유지하고 빠르게 끊는다.

의존(dependency) 관계

  • 일반적으로 한 클래스가 다른 클래스를 사용하는 경우.
    1. 클래스의 속성에서 참조할 때
    2. 매개변수, 인자로 사용될 때
    3. 메소드 내부의 지역 변수로 참조될 때
  • 1 : 연관 관계 / 2,3 : 의존 관계
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class A {

public A(){
// 생성자.
}

public void callA(){
// 의존 관계 : 이 메소드 내부에서만 c의 참조를 유지한다.
// 메소드 실행이 종료되면 c의 참조도 사라진다.
C c = new C();
c.callC();
}
}

public class C {
// 생략.
}
  • 위의 코드에서 확인할 수 있는 것처럼 짧은 시간 동안 이용하는 관계
  • UML에서는 다음과 같이 점선으로 나타낸다.

연관 관계

  • 오랜 시간 동안 같이 할 객체와의 관계
  • 예를 들어, 자동차와 자동차를 소유한 사람의 관계
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class A {
private C c;

public A() {
// 생성자.
// 연관 : 클래스 C에 대한 참조를 계속 유지하고 있음.
this.c = new C();
}

public void callA(){
this.c.callC();
}
}

public class C {
// 생략.
}

의존 관계(dependency)

클래스가 연관, 상속, 집합 관계로 엮여 있는 것은 아니지만, 한 곳이 변경되면 그것을 사용하는 다른 곳도 같이 변경해줘야 하는 관계를 표현할 때 주로 사용한다. 주의해야 할 점은 연관 관계와 달리 의존 관계의 경우에는 클래스 인스턴스의 참조를 유지하고 있지 않다는 점이다. 참조를 계속적으로 유지하게 되면 이는 연관 관계로 표현해야 한다.

주로 다음과 같은 세 가지 경우에 의존 관계로 표현한다.

  1. 한 클래스의 메소드가 다른 클래스의 객체를 인자로 받아 그 객체의 메소드를 사용한다.(가장 일반적이다.)
  2. 한 클래스의 메소드가 또 다른 클래스의 객체를 반환한다.
  3. 다른 클래스의 메소드가 또 다른 클래스의 객체를 반환한다. 이때 이 메소드를 호출하여 반환되는 객체의 메소드를 사용한다.

연관 관계(association)

한 객체가 다른 객체와 연결되어 있음을 나타낼 때 그들을 연관 관계로 지칭한다. 이 연관 관계에서 중요하게 볼 점은 연관 관계의 방향멀티플리시티이다.

연관 관계는 방향성을 가지며 양방향과 단방향으로 구분지을 수 있다.

  • 단방향 연관 관계 : 한쪽은 알지만 다른 쪽은 상대방의 존재를 모른다.
    • 화살표로 표시한다.
    • 아래의 UML House 클래스는 Person 클래스의 존재를 알고 있지만, Person은 House 클래스의 존재를 모른다.
    • House 클래스만 Person 클래스에 대한 참조값을 가지고 있고, Person은 House에 대한 어떠한 참조값도 가지고 있지 않는다.
  • 양방향 연관 관계 : 연결된 클래스들이 서로의 존재를 알고 있다.
    • 실선으로 표시한다.
    • 아래의 UML의 의미는 House와 Person 클래스는 서로의 존재를 알고 있으며, 반드시 한 사람 이상이 House에 속해야 한다는 뜻이다.

다대다 연관 관계는 양방향 연관 관계로 표현되는 것이 적절하다. 하지만 양방향 연관 관계를 구현하는 것은 복잡하기 때문에 보통 다대다 연관 관계를 일대다 단방향 연관 관계로 변환해 구현한다. -> 연관 클래스

  • 연관 클래스
    • 연관 관계에 추가할 속성이나 행위가 있을 때 사용한다.
    • 연관 클래스를 일반 클래스로 변환
      • 연관 클래스는 연관 관계가 있는 두 클래스 사이에 위치하며, 점선을 사용해 연결한다.
      • 이 연관 클래스를 일반 클래스로 변환하여 다대다에서 일대다 연관 관계로 변환한다.

일반화 관계

  • 한 클래스가 다른 클래스를 포함하는 상위 개념일 때 두 클래스 사이에는 일반화 관계가 존재한다.
  • 객체지향 개념에서는 일반화 관계를 상속 관계(IS-A)라고 한다
  • 부모 클래스
    • 추상적인 개념이며 위의 그림에서 가전제품에 해당.
    • 자식 클래스에게 공통 속성이나 기능을 제공한다.
    • ex) 제조번호, 제조 회사 같은 공통 속성과 turnOn/Off 같은 공통 기능을 두고 자식 클래스에서 상속받아 구현할 수 있다.
  • 자식 클래스
    • 구체적인 개념이며 아래의 제품들에 해당.
  • 추상 클래스
    • 추상 메소드를 하나 이상 갖는 클래스
    • 추상 메소드
      • 부모 클래스에서 구현부 없이 선언부만 있는 함수
      • ex) turnOn/Off는 자식 클래스에서 구현함에 따라 달라지기 때문에 부모 클래스에서 추상 메소드로 선언한다.
    • 일반적인 클래스와 달리 객체를 생성할 수 없다.
  • UML에서의 표현
    • 이탤릭체 사용.

집합 관계

  • 연관 관계의 특별 경우로 전체와 부분의 관계를 명확하게 명시하고자 할 때 사용한다.
  • aggregation(집합)과 composition(구성)을 구분하는 기분은 lifeCycle이 같느냐, 같지 않느냐이다.
  • lifeCycle이란 클래스 인스턴스의 생명주기를 말하는 것으로 생성에서 소멸까지의 과정이다.
  1. 집합 관계(aggregation)
  • 한 객체가 다른 객체를 포함하는 것
    • 부분을 나타내는 객체를 다른 객체와 공유할 수 있다.
  • 전체를 가리키는 클래스 방향에 빈 마름모 표시
  • 전체 객체의 lifeCycle과 부분 객체의 lifeCycle은 독립적이다.
    • 즉, 전체 객체가 사라진다 해도 부분 객체는 사라지지 않는다.
  • 예시 : 생성자에서 참조값을 인자로 받아 필드 세팅
1
2
3
4
5
6
7
8
9
10
11
12
public class Computer{
private MainBoard mb;
private CPU c;

public Computer(MainBorad mb, CPU c){
this.mb = mb;
this.c = c;
// 집합 연관 : 부분과 전체의 관계
// 부분이 되는 객체를 외부에서 생성하여 넘겨 받는다.
// 따라서 Computer 클래스가 없어져도 부분이 되는 객체들은 사라지지 않는다.
}
}
  1. 합성 관계(Composition)
  • 부분 객체가 전체 객체에 속하는 관계
    • 부분을 나타내는 객체를 다른 객체와 공유할 수 없다.
  • 전체를 가리키는 클래스 방향에 채워진 마름모로 표시
  • 전체 객체의 lifeCycle과 부분 객체의 lifeCycle은 의존적이다.
    • 즉, 전체 객체가 없어지면 부분 객체도 없어진다.
  • 예시 : 생성자에서 필드에 대한 객체를 생성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Computer{
private MainBoard mb;
private CPU c;

// 생성자
public Computer(){
this.mb = new MainBoard();
this.c = new CPU();
// 합성 : 집합 관계 중에서도 강한 집합체의 의미를 갖는다.
// 부분을 이루는 객체가 없이는 전체가 아무런 의미를 갖지 못한다.
// Computer 클래스가 사라져 버리면 내부에서 생성된 MainBoard, CPU도 같이 사라진다.
}
}

aggregation과 composition을 쉽게 설명하면 모자와 안경을 쓴 사람을 생각해보자. 이 사람을 구성하고 있는 요소에는 눈,팔,다리와 같이 사람이 죽으면 같이 없어지는 요소들이 있고, 안경,모자와 같이 바꿔 사용할 수 있는 요소들이 있다.

즉, 눈,팔,다리는 사람과 lifeCycle이 같은 Composition 관계이고 안경이나 모자는 Aggregation 관계인 것이다.

인터페이스와 실체화 관계

  • 인터페이스란
    • 책임이며, 어떤 객체의 책임이란 객체가 해야 하는 일 또는 객체가 할 수 있는 일이다.
    • 즉, 객체가 외부에 제공하는 서비스나 기능은 객체가 수행하는 책임으로 본다.
    • 공통되는 능력이 있는 것들을 대표하는 관점
  • UML에서의 인터페이스 표현
    • 빈 삼각형과 점선을 이용
  • 객체 지향 개념에서는 실체화 관계를 can do this 관계라고 한다.
1
2
3
4
5
6
7
8
9
10
public interface Flyable{
// 생략.
}

public class Plane implements Flyable{
// 생략.
}
public class Bird implements Flyable{
// 생략.
}

참고