개발자 끄적끄적
클래스 다이어그램(Class Diagram) 본문
<클래스 다이어그램>
- 문제나 해결책의 정적인 구조 표현
- 클래스와 그들간의 관계 표현
- 건물을 설계할 때도 평면도, 입면도, 투시도, 조감도 등 하나의 건축물을 다양한 관점에서 표현한다
*유스케이스 다이어그램
- 시스템을 블랙박스로 본다. 즉, 내부 구조는 표현하지 않는다
<클래스>
- UML의 클래스 표현
- 세 부분으로 나누어진 박스로 표현
- 가장 윗부분 : 클래스 이름 중간 부분 : 마시막 부분 : 연산
<클래스>
- 접근제어자
- public(+) : 어떤 클래스의 객체에서도 접근 가능
- protected(#) : 이 클래스와 상속 관계에 있는 하위클래스의 객체들만 접근 가능
- package(~) : 동일 패키지에 있는 클래스의 객체들만 접근 가능
- private(-) : 이 클래스로부터 생성되어진 객체들만 접근 가능
<속성과 오퍼레이션 표기>
- 속성 : [+], [-], [#], [~] 이름 : 타입[다중성 정보][=초기값]
- 오퍼레이션 : [+], [-], [#], [~] 이름(인자1 : 타입1, ..., 인자n : 타입n) : 반환 타입
- ex)
Course
- id : String
- name : String
- numOfStudents : int=0
------------------------------
+addStudent(s : Student): void
+deleteStudent(id : int) : void
+averageScore(): int <- __(under bar : static)
<Java Code>
class Course{
private String id;
private String name;
private int numOnStudents=0;
public void addStudent(Student s){ }
pubic void deleteStudent(int id){ }
public static int averageScore() { }
}
<제약>
- 또는 {} 이용
<관계>
- 객체지향 시스템은 상호관계를 맺는 여러 클래스에서 생성된 객체들이 기능을 수행한다
- 연관관계(Association)
- 클래스들이 개념상 서로 연결되었음을 나타낸다.
실선이나 화살표로 표기하며 보통은 한 클래스가 다른 클래스에서 제공하는 기능을 사용하는 상황일 때 표시한다
- 일반화 관계(Generalization)
- 객체지향 개념에서는 상속 관계라고 한다. 한 클래스가 다른 클래스로 포함하는 상위 개념일 때 이를 IS-A 관계라고 하며 UML에서는 일반화 관계로 모델링한다.
속이 빈 화살표를 사용해 표시한다
- 집합 관계(Composition, Aggregation)
- 클래스들 사이의 전체 또는 부분 같은 관계를 나타낸다. 집약(Aggregation)관계와 합성(Composition)관계가 존재한다
- 의존 관계(Dependency)
- 인간 관계와 같이 한 클래스가 다른 클래스에서 제공하는 기능을 사용할 때를 나타낸다.
차이점은 두 클래스의 관계가 한 메서드를 실행하는 동안 같은, 매우 짧은 시간만 유지된다는 점이다.
점선 화살표를 사용해 표시한다
- 실체화 관계(Realization)
- 책임들의 집합인 인터페이스와 이 책임들을 실제로 실현한 클래스들 사이의 관계를 나타낸다
상속과 유사하게 빈 삼각형을 사용하여 머리에 있는 실선 대신 점신을 사용해 표시한다
<연관 관계에서의 역할>
- 연관 관계에서 각 클래스 객체의 역할은 클래스 바로 옆 연관 관계를 나타내는 선 가까이 기술
- 역할 이름은 연관된 클래스의 객체들이 서로를 참조할 수 있는 속성의 이름으로 활용
<다중성>
- 1(다중성 표기) : 엄밀하기 1
- * : 0 또는 그 이상
- 0..* : 0 또는 그 이상
- 1..* : 1 이상
- 0..1 : 0 또는 1
- 2..5 : 2또는 3또는 4또는 5
- 1,2,6 : 1 또는 2또는 6
- 1, 3...5 : 1또는 3또는 4또는 5
- ex)
Person(1) -- --> Phone(-phone,2)
<Java Code(1)>
class Person{
private Phone[2] phone;
}
class Phone{
}
---------------------------------
<클래스 다이어그램>
Person
-phones:Phone[2]
Phone
---------------------------------
- ex) 연관관계가 2개 일 때
Person -- --> Phone(-homePhone)
-- --> Phone(-officePhone)
<Java Code>
class Person{
private Phone homePhone;
private Phone officePhone;
}
*하단의 클래스 다이어그램에 연관 관계가 명시적으로 표현되지 않았음을 주목
<연산관계>
- 연관된 클래스 상에 실선을 그어 표시
- 두 클래스 상이의 관계가 명확한 경우에 이름을 사용하지 않아도 된다
- 역할은 연관관계를 나타내는 실선을 선택한 후에 r1, r2를 사용하여 표기
- 연관관계는 클래스의 속성으로 구현한다
- 다중성을 해석할 때 연관관계를 참여하는 각 클래스의 인스턴스 하나의 관점에서 해석
- ex)
Person(1, owner) -- owns -- Car(0..*, cars) //연결관계, 연관관계 이름은 owns
<Java Code>
class Person{
Car[] cars;
}
class Car{
Person owner;
}
<양뱡향, 단방향 연관 관계>
- 양방향 연관 관계
- 두 클래스를 연결한 선에 화살표를 사용하지 않음, <-> (x)
- 서로의 존재를 인지
- 단방향 연관 관계
- 한 쪽으로만 방향성이 있는 관계
- 한 쪽은 알지만 다른 쪽은 상대방의 존재를 모른다는 의미
- ex) Person(-owner) -- owns --> (-cars)Car
- 사람은 자신이 소유한 자동차(들)에 대해 알지만, 자동차는 자신이 소유자에 대해 모른다.
즉, 자동차 클래스에는 person 클래스를 참조하는 속성이 없다
<Java Code>
class Car{ }
<연관 클래스>
- 연관 관계에서 추가할 속성이나 행위가 있을 때 사용
- 갑돌이는 마스크를 2020년 4월 10일 10장 주문했다.
- 갑순이는 라며을 2019년 11월 18일 2박스 주문했다.
- 길동이는 컴퓨터를 2020년 3월 3일 1대 주문했다.
- 갑순이는 컴퓨터를 2018년 10월 1일 2대 주문했다.
- 길동이는 마스크를 2020년 4월 2일 5장 주문했다.
- ex) 고객(1) -- (*)주문(*) -- 제품(1)
고객(1) //Class
-name : String
제품(1) //Class
-name : String
주문(*)//Class, 점선으로 표기
-orderDate : Date
-quantity : int
*연관클래스를 만들어 연관 자체의 정보를 속성으로 두어 관리한다
즉, 주문에 대한 정보를 연관 클래스로
주문__//Instance
-orderDate=2020/4/10
-quantity : 10
*갑돌이가 주문객체와 주문 클래스간의 관계가 생성
-------------------------------------
: 고객__ //Instance
name="길동"
: 고객__ //Instance
name="갑순"
: 고객__ //Instance
name="갑돌"
-------------------------------------
: 제품__//Instance
name = "마스크"
: 제품__//Instance
name= "컴퓨터"
: 제품__//Instance
name = "라면"
*갑돌이, 갑순이, 길동이 : 고객 클래스의 인스턴스
*마스크, 라면, 컴퓨터 : 제품 클래스의 인스턴스
*객체 다이어그램 : 객체와 객체간의 링크 관계를 보여준다
*객체도 박스로 표현
- 객체이름 : 클래스(객체이름은 생략 가능) 언더라인(_)
*객체 다이어그램에서 객체 간의 관계를 링크(link)라고 한다. 실선으로 표현(화살표x)
*링크에는 링크이름을 쓰지 않는다
*객체간의 관계를 파악하여 객체 다이어그램을 작성한 후에 클래스 다이어그램을 작성할 수도 있다.
*주문날짜와 주문 수량은 연관관계 자체의 속성이다
- ex)
사물 -- (*)사건(*) -- 사물
- 사물과 사물 사이에 발생하는 사건 내역(히스토리) 관리하기 위한 시스템 구조
<실습>
- '학생'들이 '책'을 '대출'할 때 대출일지와 반납일자 정보를 관리해야 하는 상황을 클래스 다이어그램을 모델링하라
학생(*) -- 대출 -- (*)책
대출 //연관클래스의 이름
------------
-대출날짜 : Date
-반납날짜 : Date
학생 //Class(학생-대출, 실선)
대출 //Class
-대출날짜 : Date
-반납날짜 : Date
책 //Class(대출-책, 실선)
<일반화>
- 일반화는 "is a kind of" 관계
- 가전제품 : 부모 클래스(슈퍼 클래스)
- 세탁기, TV, 식기세척기 : 자식 클래스(서브 클래스)
- 세탁기 is a kind of 가전제품
- TV is kind of 가전 제품
- 식기세척기 is a kind of 가전 제품
-ex) 연관관계
사람(Class) --> 냉장고(Class)
--> 세탁기(Class)
--> 식기세척기(Class)
냉장고, 세탁기, 식기세척기 등 포함하는 것을 만들면(일반화) -> 가전제품
일반화(상속관계x, 일반화관계o)
사람 --> 가전제품(단방향)
가전제품 --> 식기세척기(참조x)
가전제품 --> 세탁기
가전제품 --> 냉장고
가전제품 --> 전자레인지(기존의 클래스다이어그램을 놔두고 하위개념으로 추가 가능)
*가전제품은 추상클래스 -> 실제 인스턴스가 될 수 없다 -> <<abstract>> 가전제품
*추상적 개념은 추상 클래스로 모델링
- "<<", ">>"는 꺽쇠 괄호(angle=braket)두 개가 아니라 quillements(기르멧)라 불리는 하나의 문자("<<", ">>")이다. 즉, 기르멧 문자를 이용하여 추상 클래스를 만든다.
이와 같이 UML을 새로운 개념을 반영하여 확장하는 메커니즘을 스테레오타입(Stereotype)이라고 한다
<Java Code(일반화 관계)>
class 사람{
가전제품 m;
public void setM(가전제품 m){
this.m=m;
}
public 가전제품 getM(){
return this.m;
}
}
*속성에 값을 설정하는 setter와 설정된 값을 반환하는 getter를 보통 속성마다 만든다
---------------------------------------
abstract class 가전제품{
}
class 식기세척기 extends 가전제품 {...}
class 세탁기 extends 가전제품 {...}
class 냉장고 extends 가전제품 {...}
class 전자레인지 extends 가전제품 {...}
class 김치냉장고 extends 가전제품 {...} //추가
<집합 관계 - 연관관계의 특수한 경우>
- 연관관계가 전체와 부분 사이의 관계를 나타낼 때, 전체와 부분간의 관계
- 집약(Aggregation)
- 전체를 나타내는 객체와 부분을 나타내는 개체의 라이프 타임이 독립적 : 약한결합
- 부분을 나타내는 객체를 다른 객체와 공유 가능
- 빈 마름모로 표시
- ex) 연관관계 이름은 쓸 필요가 없다
Computer ◇-> PowerSupply
Computer ◇-> Mainboard
Computer ◇-> CPU
Computer ◇-> Memory
<Java Code>
class Computer{
private PowerSupply ps;
private Mainboard mb;
private CPU cpu;
private Memory mem;
//인자로 전달되기 때문에 class Computer를 제거해도 라이프타임은 독립적으로 결합 -> 약한결합
public Compuer(PowerSupply ps, Mainboard mb, CPU cpu, Memory mem){
this.ps = ps;
this.mb = mb;
this.cpu = cpu;
this.mem = mem;
}
}
전체(whole) : Computer //점선
부분(Part) : Power Supply, Mainboard, CPU, Memory //점선
*전체를 나타내는 쪽에 빈 다이어몬드 표시
*전체에는 부분이 있다/가지고 있다.
전체는 부분 무엇 무엇을 가지고 있다.
전체는 무엇 무엇으로 구성된다.
- 합성(Composition)
- 전체를 나타내는 객체에 부분을 나타내는 개체의 라이프 타임이 종속적
- 전체 객체가 사라지면 부분 객체도 사라진다 : 강한결합
- 채워진 마름모로 표시
- ex)
Computer ◆-> PowerSupply
Computer ◆-> Mainboard
Computer ◆-> CPU
Computer ◆-> Memory
<Java Code>
class Computer{ //Computer 객체가 소멸되면 부분객체도 소멸된다 -> 강한결합
private PowerSupply ps;
private Mainboard mb;
private CPU cpu;
private Memory mem;
public Computer(){ //생성자 호출
this.ps = new PowerSupply();
this.mb = new Mainboard();
this.cpu = new CPU();
this.mem = new Memory();
}
}
<실습>
체크포인트_'동아리'와 '학생' 관계에서 다음 사실을 모두 클래스 다이어그램으로 표현하라
- 학생은 한 동아리에만 가입할 수 있다
- 한 동아리에는 여러 명의 학생들이 있다
- 동아리가 없어지면 동아리에서 활동했던 학생들의 정보도 없어진다 -> Aggregation
*명사 추출법 : 클래스 후보를 추출할 때 문제기술서에서 명사 or 명사구를 추출
동아리(0..1) ◆-> (*)학생
<의존 관계>
- 한 클래스에서 다른 클래스를 사용하는 경우
- 클래스의 속성에서 참조
- 연산의 인자로 참조
- 메소드의 지역 개체로 참조
- client-server 관계
- ex) 속성을 통한 연산 관계
Professor -> (*, -lectures)Lecture //한 교수는 여러 강의를 할 수 있다
<Java Code>
class Professor{
private Lecture[] lectures;
}
class Lecture{
}
Professor{
}
Lecture{
}
*속성을 통해 연결 : 연관관계(지속적으로 연결된 관계)
- 연산의 인자나 메소드의 지역 개체로 참조
- 찰나적 관계
- ex) 의존 관계와 연관 관계
- Car : client
- GasPump : server
*의존관계는 점선 화살표로 표시되면 단방향 관계이다
<Java Code>
1. 메서드를 인자정보로서 참조
연관관계 : Car --> GasPump
class Car{
public void fillGas(GasPump g){ //메서드의 인자정보로서 참조
...
p.getGas(amount);
...
}
}
1-1.
연관관계 : Car --<<use>>--> GasPump
class Car{
public void fillGas(){
GasPump = new GasPump();
...
p.getGas(amount);
...
}
}
2. 클래스로 참조
연관관계 : Car -> GasPump
class Car{
private GasPump p = new GasPump(); //속성정보로 참조
public void fillGas();
...
p.getGas(amount); //p라는 동일한 인스턴스가 계속 유지
...
}
}
*연관관계는 인스턴스들간에 지속적으로 유지될 때 사용
class GasPump{
public void getGas(int amount)
...
}
}
3. 자동차가 사람이 소유한다, 단 사람은 자동차 한 대만을 소유한다
연관관계 : Person -> Car --> <<use>> --> GasPump
Class Person{
private Car car;
}
4. Money Class 추가
연관관계 : Person -> Car --> <<use>> --> Gas Pump
Person -> Car --> <<use>> --> Money
class Car{
public Money fill Gas(){
GasPump = new GasPump();
...
p.getGas(amount);
...
return new Money(amount);
}
}
*Gas : 가솔린 연료, GasPump : 주유기
*자동차(Car)가 연료를 채우기 위해(fillGas) 주유기(GasPump)의 getGas 서비스를 이용한다
<인터페이스와 실체화 관계>
- 인터페이스는 계약이다
- 계약을 준수하는 어떤 것이라도 사용하기 위해서
- ex) 리모콘의 책임은 가전 기기를 켜거나 끄거나 볼륨을 높이거나 낮춘다
- 어떤 공통되는 능력이 있는 것들을 대표하는 관점
-ex)
<<interface>>
Flyable
---------------
+fly() : void
Client
---------------
+a(Flyable f) : void
Bird
---------------
+fly()
Airplane
---------------
+fly()
Flyable : provided interface
---------------
+fly() : void
<Java Code>
1. Bird
연관관계 : Bird --▷ Flyable
class Bird implements Flyable{
public void fly(){
... //새가 나는 것을 구현
}
}
2. Airplane
연관관계 : Airplane --▷ Flyable
class Airplane implements Flyable{
public void fly(){
... //비행기가 나는것을 구현
}
}
3. Client
연관관계 : Client --> Flyable
+a(Flyable f) : void
*이 인터페이스(계약)을 준수하기 위해서는 fly() 서비스를 제공하면 된다
*인터페이스와 클래스는 Realization(실체화) 관계가 있다
*클래스가 사용하는 인터페이스를 required interface를 사용하여 모델링
*서비스를 제공하는 클래스가 변경되어도 그 서비스를 사용하는 클라이언트 쪽 코드는 영향을 주지 않는다
<클래스 다이어그램 작성>
- 유스케이스 기술서 등을 포함한 대상 프로젝트에 관한 여러 문서들에 나타나 있는 명사나 명사구를 추출하는 것이다
- 절차
- 요구사항에서 명사나 명사구를 추출하여 클래스 후보 추출(클래스 추출)
- 속성 식별(속성 추출)
- 일반화 관계 식별(클래스 간 관계 추출)
- 연관관계 식별
*명사, 명사구 => 클래스 후보 식별
<클래스를 추출할 때 고려할 사항(1)>
- 전체 시스템을 표현하는가?
- 만약 어떤 사물이 전체 시스템을 표현한다면 이를 클래스 후보에서 제외하는 것이 보통
- 다른 클래스와 중복되느냐?
- 만약 다른 클래스와 중복된다면 클래스 후보에서 제외한다
- 애매모호하냐?
- 클래스의 범위를 명확하게 할 수 없는 경우에는 클래스의 후보에서 제외한다
- 너무 상세하냐?
- 너무 상세한 경우는 클래스라기 보다는 클래스의 인스턴스, 즉 객체로 모델링 하는 것이 좋다
<클래스를 추출할 때 고려할 사항(2)>
- 속성 또는 속성이 가질 수 있는 값이냐?
- 속성은 클래스의 특징을 표현한다
- 연산이냐?
- 연산으로 분류되는 것은 클래스 후보에서 제외한다
<클래스 다이어그램 실습>
- ex) 예제 : University System
- A 'university' consists of multiple 'faculites' which are composed of various 'institutes'. Each faculty and each institute has a 'name'. An 'address' is known for each institute
- Each faculity is led by a 'dean', who is an 'employee' of the university.
- The 'total number' of employees is known. Employees a 'social security number', a 'name', and an 'email address'. There is a distinction between 'research' and 'administrative' per sonnel.
- 'Research associates' are assigned to at least one institute. The 'field of study' of each research associate is known. Futhermore, research associates can be involved in 'projects' for a certain 'number of hours', and the 'nema', 'starting date', and 'end date' of the projects are known. Some research associates teach 'courses'. They are colled 'lectures'.
- Courses have a 'unique number(ID), a 'name' and a 'weekly duration' in hours.
*Dean은 클래스라기보다는 Employee 클래스와 Faculty 간의 관계에서 수행하는 역할
Project
-----------------
-name : String
-start : Date
-end : Date
Participation
-----------------
-hours : int
[연관관계]
Research Associate(1..*) - (0..*)Project
- 한 프로젝트에는 여러명의 연구원이 참여한다
Research Associate(1..*) -- Participation -- (0..*)Project
연관관계 속성 관계 : Participation
Institute(학과)
-----------------
-name : String
-address : String
[연관관계]
Research Associate(1..*) - (1..*)Institute
- 한 학과는 여러 연구원을 가지고 있다
Faculty(학부)
-----------------
Employee
-----------------
-totalNumber : int //class의 속성 -> 정적 속성(__)으로
-ssn : int
-email : String
-name : String
[연관관계]
Employee(-dean, 1) - leads - (0..1)Faculty
*Employee 클래스와 Faculty 클래스 간의 연관관계 "leads"에서 Employee의 역할은 dean이다
Administractive Employee(행정직원)
-----------------
Research Associate(연구원)
-----------------
-fieldOfStudy : int
[일반화관계]
Administractive Employee -▷Employee
Research Associate -▷ Employee
Course(교과목)
-----------------
-ID
-name
[연관관계]
Lecturer(1..*) -teaches- (1..*)Course
Lecturer(강사)
-----------------
[일반화관계]
Lecturer -▷ Research Associate
*Lecturer Is (a kind of) Research Associate => 일반화 관계
<개념간의 관계(일반화 관계 및 연관 관계 식별)>
- 클래스들간의 논리적 관계를 찾아라. 이 때 이 관계가 지속적일 때 의미가 있다.
- 분석 초기에는 연관 관계가 분명하게 드러나지 않을 수 있기 때문에 너무 조급하게 연관 관계를 찾으려고 노력하지 말라. 후에 객체간의 상호작용을 분석할 때 더욱 명확하게 연관관계가 드러날 수 있다
- Larman의 가이드라인
- Need to know 관계 : 클래스가 지속적으로 존재할 필요가 있는 클래스들의 관계에 초점을 두어라
- 중복되거나 이미 다른 연관관계에서 추출할 수 있는 관계는 가능한 피해라
<Key Point>
- 일반화 관계는 is a kind of 관계이지만, 실체화 관계는 can do this의 관계이다
<객체 다이어그램>
- 클래스 다이어그램의 인스턴스. 즉, 사례를 보여준다
- 학생은 반드시 한 학교에 소속되어야 한다
- 학생은 1개의 학교 밖에 소속할 수 없을 것
- 학교는 학생이 없거나 여러명 있을 수 있다
*객체 다이어그램(Object Diagram) : 객체 정보를 보여준다
'소프트웨어공학' 카테고리의 다른 글
순차 다이어그램 (0) | 2024.04.12 |
---|---|
Usecase Diagram (1) | 2024.04.03 |
프로토타입(Prototype) (0) | 2024.04.01 |