*이 글은 위 링크의 공부를 목적으로 내용을 필사하거나 정리했습니다.
최근 튜토리얼을 따라하면서 유연한 클래스의 작성이 중요하단 생각이 들었습니다. 어떻게 하면 이 튜토리얼처럼 유연하게 클래스를 구성할 수 있을지 고민하다가 문득 UML 다이어그램이 생각났습니다. 얼핏 들어보기만 했던 거였는데, 이걸 활용하면 클래스를 좀 더 넓은 시야로 바라볼 수 있을거란 생각이 들었습니다.
또 튜토리얼을 단지 따라하는 선에서 그치는게 아닌 튜토리얼의 내용을 더욱 내 것으로 소화시키기 위해서 클래스를 그림으로 기억하는 것도 꽤 훌륭한 방법인것 같아습니다.
이런 이유로 UML 클래스 다이어그램이 무엇인지 알아보게 됐습니다.
클래스 다이어그램이란
시스템을 구성하는 클래스들 사이의 관계를 표현해주는 그림 도식입니다.
클래스의 표현
클래스는 3가지 칸으로 구성됩니다. 가장 윗 부분에는 클래스 명이 들어가고, 중간 부분에는 속성(클래스의 특징, 변수)이 들어갑니다. 마지막 부분에는 연산(메서드, 클래스가 수행하는 책임)이 들어갑니다.
그림으로 보면 이렇습니다.
Player |
+moveSpeed -moveDir #targetPosition |
-Move() +TraceTarget() |
경우에 따라서 속성(변수)과 연산(함수)부분은 생략하기도 합니다. 예를 들어 속성으로 흐름을 분석하기 위해 다이어그램을 쓰는 경우에요.
위에서 이름 앞에 -,+,#과 같은 기호들이 작성됐는데 순서대로 private, public, protected를 의미합니다.
이렇게 다이어그램을 표현할 때 분석 단계와 설계 단계에서의 표현 방식이 다소 다릅니다.
클래스 간 관계
UML에서 제공하는 클래스들 사이의 관계는 아래와 같습니다.
1. 연관 관계(association)
표시 : 실선이나 화살표
설명 : 클래스들이 개념상 서로 연결됐음을 나타낸다. 보통은 한 클래스가 다른 클래스에서 제공하는 기능을 사용하는 상황일 때 표시한다.
- 한 클래스가 다른 클래스와 연관 관계를 가지면 각 클래스의 객체는 해당 연관 관계에서 어떤 역할을 수행합니다. 이 때 두 클래스의 역할 표현을 역할 관계 이름이라 부릅니다. 또한 연관관계는 방향성을 가지고 있습니다. 양방향은 실선으로, 단방향은 화살표로 표시됩니다.
- 단방향(화살표)의 경우 한 쪽은 알지만 다른 쪽은 상대방의 존재를 모릅니다. 사람과 핸드폰의 관계를 예로 들 수 있습니다.
- 양방향(실선)의 경우 두 클래스의 객체들이 서로를 인지합니다. 상담의사와 환자를 예로 들 수 있습니다.
2. 일반화 관계(generalization)
표시 : 속이 빈 화살표
설명 : 객체지향 개념에서 상속관계라고 말합니다. 한 클래스가 다른 클래스를 포함하는 상위 개념일 때 이를 IS-A 관계라고 하며 UML에서는 일반화 관계로 모델링합니다.
- 한 클래스가 다른 클래스를 포함하는 상위 개념일 때 두 클래스 사이에는 일반화 관계가 존재합니다. 이를 객체지향 개념에선 상속관계라고 합니다.
- 부모 클래스는 추상적인 개념이며, 삼각형 표시가 있는 쪽을 의미합니다.
- 자식 클래스는 추상적인 개념을 물려받은 구체적인 개념입니다. 삼각형 표시가 없는 쪽입니다. 부모 클래스는 자식 클래스의 공통적인 속성과 연산을 제공하는 틀입니다.
3-1. 집합관계 - 집약 관계(aggregation)
표시 : 속이 빈 다이아몬드
설명 : 클래스들 사이의 전체 또는 부분 같은 관계를 나타냅니다. 전체 객체의 라이프타임과 부분 객체의 라이프 타임은 독립적입니다. 즉, 전체 객체가 사라져도 부분 객체는 남아있습니다. (라이프 타임 독립적)
3-2. 집합관계 - 합성 관계(composition)
표시 : 속이 찬 다이아몬드
설명 : 클래스들 사이의 전체 또는 부분 같은 관계를 나타냅니다. 전체 객체의 라이프 타임과 부분 객체의 라이프 타임이 의존적입니다. 즉, 전체 객체가 사라지면 부분 객체도 함께 사라집니다. (라이프 타임 의존적)
4. 의존 관계(dependency)
표시 : 점선 화살표
설명 : 연관 관계와 같이 한 클래스가 다른 클래스에서 제공하는 기능을 사용할 때 나타냅니다. 연관 관계와 차이점은 두 클래스의 관계가 한 메서드를 실행하는 동안과 같은, 매우 짧은 시간만 유지된다는 점입니다.
연관 관계와 의존 관계가 헷갈릴 수 있습니다. 둘 모두 한 클래스에서 다른 클래스를 사용하기 때문입니다. 결정적인 차이는 연관 관계는 클래스A가 클래스B를 멤버 변수로 가지고 있고, 의존 관계는 클래스A가 클래스 B의 메서드를 가지고 있습니다. 혹은 클래스 B를 메서드의 인자로 받습니다.
5. 실체화 관계(realization)
표시 : 빈 삼각형과 점선
설명 : 책임들의 집합인 인터페이스와 이 책임들을 실제로 실현한 클래스들 사이의 관계를 나타냅니다.
인터페이스란 책임입니다. 어떤 객체의 책임이란 객체가 해야 하는 일 혹은 객체가 할 수 있는 일을 의미합니다. 인터페이스의 경우 클래스 명에 <<interface>>를 달아줍니다. 그리고 인터페이스도 마찬가지로 객체 지향 개념에서 일반화 관계에 속합니다.
클래스간 관계 : EX 스타크래프트
마지막으로 클래스간의 관계 일반화 관계(Generalization), 실체화 관계(Realization), 연관 관계(Association), 의존 관계(Dependency)에 대해서 스타크래프트 예제를 통해 살펴보겠습니다.
1. 일반화 관계 (Generalization)
이 경우 마린이나 매딕이 상위 클래스인 Unit을 상속받습니다. Unit에선 Name, Health를 추상적으로 선언합니다. 그리고 메소드로 Move()를 선언합니다. 마린과 매딕은 유닛에서 상속받은 것 말고도 각자의 특수한 스킬이나 액션에 따른 다른 멤버 변수를 선언 할 수 있습니다. 이는 메서드를 추가하여 구현하거나, 상속받은 메서드를 추상 오버라이드해서 구현할 수 있습니다.
2. 실체화 관계 (Realization)
실체화 관계는 인터페이스 구현을 표현합니다. 인터페이스도 일반화 관계와 마찬가지로 상속을 하기 때문에 비슷한 개념에 혼동이 올 수 있습니다. 상속과 인터페이스의 다른 점은 상속은 직접 상위 클래스를 받아서 해당 클래스의 기능과 멤버 변수, 메소드 등을 상속받아 포함시킵니다. 인터페이스는 서로 완전히 다른 클래스라도 인터페이스만 준수하면 동일한 기능들이 구현 될 수 있습니다. 단, 멤버변수는 포함되지 않습니다.
위 내용을 보시면 Building을 Barracks, Factory, Bunker에서 상속받습니다. 고로 세 건물은 Building의 Health와 Ammor 멤버 변수를 받아오고 Construct(), UnderAttak()기능도 부여받습니다. 이 때 테란의 특수기능 건물 띄어서 이동하기를 구현하려합니다. 이 기능을 똑같이 Building에 메서드로 추가하게 되면 Bunker도 띄어지는 건물이 되버리는 상황이 되버립니다. Bunker는 이동이 불가능해야합니다. 이 문제 해결을 위해 인터페이스를 사용하여 특정 기능을 특정 클래스에 약속 시킬 수 있습니다. Barracks와 Factory는 IBuilingMove의 Move(), Land(), Fly()를 반드시 사용해야합니다.
3. 연관 관계(Associaion)
단방향과 양방향이 존재합니다. 단방향은 대상이 자신의 클래스를 모르는 상황에 쓰이며, 양방향은 서로 연관돼 있는 상태에 쓰입니다.
첫 번째 연관관계에서 마린은 총이라는 클래스를 멤버 변수로 가지고 있지만, Gun은 마린이 있다는 사실도 모릅니다.
두 번째 집합관계 - 집약관계를 나타냅니다. Factory가 파괴돼도 FactoryAddOn은 독립적으로 남아있습니다.
세 번째 집합질문 - 합성관게를 나타냅니다. 라이프 사이클이 서로 갇습니다.
4. 의존 관계(Dependency)
위 경우 한 객체가 다른 객체를 소유하진 않습니다만, 다른 객체의 변경에 따라 같이 변경을 해줘야합니다. 일반적으로 아래의 상황일때 사용하게 됩니다.
(1) 다른 객체를 파라미터로 받아서 그 메서드를 사용합니다.
(2) 객체의 메서드 안에서 다른 객체를 생성해서 리턴합니다.