안녕하세요. 개발자 Jindory입니다.
오늘은 클래스 다이어그램의 정의와 클래스간의 관계에 대해서 글을 작성해보려고 합니다.
[ 글 작성 이유 ]
회사에서 동료 개발자들과 같이 일하기 위해서 요구사항 분석 및 설계전에 클래스 다이어그램을 정리할 때 클래스 다이어그램 작성법 및 사용법에 대해서 잘 모르는것 같아 이번 기회에 정리해보고자 합니다.
1. 클래스 다이어그램이란?
클래스 다이어그램(Class Diagram)이란 UML(Undefined Modeling Language)의 Structural Diagran(구조 다이어그램)의 하나로, 시스템의 구조와 클래스 간의 관계를 나타낼 때 사용하는 Diagram입니다. 클래스(Class), 속성(Attribute), 메서드(Method), 클래스 간의 관계 등을 시각적으로 표현할 때 사용합니다. 시스템의 정적인 구조를 정리하며 개발 과정에서 개발해야할 클래스간의 관계 및 구조를 이해하는데 도움이 됩니다.
1-1 클래스 다이어그램 구성요소
클래스 다이어그램은 아래와 같이 4개의 요소로 구성되어 있습니다.
- 클래스(Class): 객체의 설계도로, 속성과 메서드로 구성됩니다.
- 속성: 클래스의 특성을 나타냅니다.
- 메서드: 클래스의 기능을 나타냅니다.
- 관계: 클래스 간의 관계를 나타내며, 연관관계(Association), 상속관계(Inheritance), 실현관계(Realization) 등이 있습니다.
속성의 접근제어자와 객체와의 관계도 나타낼 수 있는데, 아래의 그림과 같이 나타낼 수 있습니다.
- + : public으로 모든 클래스에서 접근 가능
- - : private로 같은 클래스안에 있는 멤버에서만 접근 가능
- # : protected로 같은 패키지 안의 모든 클래스와, 다른 패키지의 자식 클래스에서 접근 가능
- ~ : default로 같은 패키지안의 클래스에서만 접근 가능
- {readonly} : final의 의미로 읽기만 가능하고 수정이 불가능
- 밑줄 : static을 의미
- [*], [0...1] : 리스트 형식의 객체에 사이즈를 뜻하며, [*]는 아직 사이즈가 정해지지 않았을 경우, [0...1]는 0개에서 1개인 경우를 나타냄.
속성을 작성시 {접근제어자} {필드명} : {타입} 순서로 작성하며,
메서드 작성시 {접근제어자} {메서드명} {파라미터} : {반환타입} 순서로 작성합니다.
1-2 클래스 다이어그램 관계
클래스 다이어그램은 클래스에 대한 정의 뿐만 아니라 클래스 간의 관계도 나타낼 수 있습니다. 아래의 그림은 클래스간의 관계를 나타낼 수 있는 6가지 유형에 대해 도식화한 내용입니다. 각각의 관계가 어떤 관계인지 하나씩 알아보도록 하겠습니다.
1-2-1 Association(연관)
- Association(연관)은 두 클래스 간의 참조 관계를 나타냅니다.
- 방향이 있는 실선과 방향이 없는 실선 모두 표현할 수 있습니다.
- 일대일, 일대다, 다대일, 다대다 관계를 모두 나타낼 수 있습니다.
Association(연관)을 Java 소스코드로 표현하면 아래와 같습니다.
< 일대일 관계 >
// People 클래스
public class People {
private int id;
private String name;
private Gender gender;
// 생성자, Getter/Setter 메서드 생략
}
// Gender 클래스
public class Gender {
private int id;
private String genderType;
// 생성자, Getter/Setter 메서드 생략
}
- People 클래스에는 Gender 클래스의 인스턴스가 포함되어 있습니다.
- 한명의 사람은 한개의 성별만 가질 수 있습니다.
- 한 사람이 하나의 성별만 가지게 함으로써 일대일 관계를 구현한 것입니다.
< 일대다 관계 >
// Student 클래스
public class Student {
private int id;
private String name;
private List<Subject> subjects;
// 생성자, Getter/Setter 메서드 생략
}
// Subject 클래스
public class Subject {
private int id;
private String name;
private int credits;
// 생성자, Getter/Setter 메서드 생략
}
- Student 클래스는 여러개의 Subject 클래스 인스턴스가 포함될 수 있습니다.
- 한명의 학생이 여러개의 과목을 수강할 수 있는 관계를 표현한 것입니다.
- Subject는 한명의 Student에만 속하도록 하여 일대다 관계를 구현할 수 있습니다.
< 다대일 관계 >
// Student 클래스
public class Student {
private int id;
private String name;
private Subject subject;
// 생성자, Getter/Setter 메서드 생략
}
// Subject 클래스
public class Subject {
private int id;
private String name;
private int credits;
private List<Student> students;
// 생성자, Getter/Setter 메서드 생략
}
- Student 클래스의 인스턴스는 하나의 Subject 클래스 인스턴스에 속할 수 있습니다.
- 하나의 과목에 여러명의 학생이 수강하는 관계를 표현한 것입니다.
- Student는 한 Subject에만 속하도록 하여 다대일 관계를 구현한 것입니다.
< 다대다 관계 >
// Professor 클래스
public class Professor {
private int id;
private String name;
private List<Student> students;
// 생성자, Getter/Setter 메서드 생략
}
// Student 클래스
public class Student {
private int id;
private String name;
private List<Professor> professors;
// 생성자, Getter/Setter 메서드 생략
}
- Professor 클래스의 인스턴스는 여러 명의 Student 클래스 인스턴스와 관련될 수 있습니다.
- Student 클래스의 인스턴스도 여러 명의 Professor 클래스 인스턴스와 관련될 수 있습니다.
- 여러명의 교수님이 여러명의 학생과 관계를 맺음으로써 다대다 관계를 구현한 것입니다.
1-2-2 Inheritance(상속)
상속은 Java의 extend를 의미하며, 부모 클래스의 멤버를 자식 클래스에게 물려주는것을 의미합니다.
- 한 클래스가 다른 클래스의 속성과 메서드를 상속받는 관계를 나타낼 때 사용합니다.
- UML 다이어그램에서는 화살표로 연결하며, 화살표 끝에 빈 삼각형이 위치합니다.
- 상위 클래스(부모 클래스)의 특성을 하위 클래스(자식 클래스)가 물려 받습니다.
Inheritance(상속)를 Java 소스코드로 표현하면 아래와 같습니다.
// 부모 클래스 Animal
public class Animal {
protected String species;
protected String name;
protected int legs;
protected String taste;
public Animal(String species, String name, int legs, String taste) {
this.species = species;
this.name = name;
this.legs = legs;
this.taste = taste;
}
public void eat() {
System.out.println(String.format("%s is eating.", this.name));
}
public void sleep() {
System.out.println(String.format("%s is sleeping.", this.name));
}
public void cry() {
System.out.println(String.format("%s is crying.", this.name));
}
}
// 자식 클래스 LandAnimal
public class LandAnimal extends Animal {
private String hairType;
private int speed;
public LandAnimal(String species, String name, int legs, String taste, String hairType, int speed) {
super(species, name, legs, taste);
this.hairType = hairType;
this.speed = speed;
}
public void dig() {
System.out.println(String.format("%s is digging.", this.name));
}
public void climb() {
System.out.println(String.format("%s is climbing.", this.name));
}
}
// 자식 클래스 MarineAnimal
public class MarineAnimal extends Animal {
private String skinType ;
private int fins;
public MarineAnimal(String species, String name, int legs, String taste, String skinType, int fins) {
super(species, name, legs, taste);
this.skinType = skinType;
this.fins = fins;
}
public void swim() {
System.out.println(String.format("%s is swimming.", this.name));
}
public void dive() {
System.out.println(String.format("%s is diving.", this.name));
}
}
// 자식 클래스 FlyingAnimal
public class FlyingAnimal extends Animal {
private String wingType;
private int feathers;
public FlyingAnimal(String species, String name, int legs, String taste, String wingType, int feathers) {
super(species, name, legs, taste);
this.wingType = wingType;
this.feathers = feathers;
}
public void fly() {
System.out.println(String.format("%s is flying.", this.name));
}
}
1-2-3 Realization(실체화/구체화)
실체화는 인터페이스와 그 인터페이스를 구현하는 클래스와의 관계를 나타냅니다.
- UML 다이어그램에서는 점선 화살표로 연결하며, 화살표 끝에 빈 삼각형이 위치합니다.
- 인터페이스의 메서드를 실제로 구현하는 클래스와의 관계를 표현합니다.
Realization(실체화)를 Java 코드로 구현하면 아래와 같습니다.
// 인터페이스 CookBook
interface CookBook {
void prepareIngredients();
void cook();
}
// 한식요리사 클래스
class KoreanChef implements CookBook {
@Override
public void prepareIngredients() {
System.out.println("한식 재료를 준비합니다.");
}
@Override
public void cook() {
System.out.println("한식을 조리합니다.");
}
}
// 중식요리사 클래스
class ChineseChef implements CookBook {
@Override
public void prepareIngredients() {
System.out.println("중식 재료를 준비합니다.");
}
@Override
public void cook() {
System.out.println("중식을 조리합니다.");
}
}
// 일식요리사 클래스
class JapaneseChef implements CookBook {
@Override
public void prepareIngredients() {
System.out.println("일식 재료를 준비합니다.");
}
@Override
public void cook() {
System.out.println("일식을 조리합니다.");
}
}
// 이탈리아요리사 클래스
class ItalianChef implements CookBook {
@Override
public void prepareIngredients() {
System.out.println("이탈리아 요리 재료를 준비합니다.");
}
@Override
public void cook() {
System.out.println("이탈리아 요리를 조리합니다.");
}
}
// 양식요리사 클래스
class WesternChef implements CookBook {
@Override
public void prepareIngredients() {
System.out.println("양식 요리 재료를 준비합니다.");
}
@Override
public void cook() {
System.out.println("양식 요리를 조리합니다.");
}
}
1-2-4 Dependency(의존)
의존 관계는 한 클래스가 다른 클래스를 사용하지만, 그 클래스의 구성요소가 아닌 경우를 나타냅니다.
- 한 클래스가 다른 클래스의 기능을 일시적으로 사용하는 관계를 나타냅니다.
- UML 다이어그램에서는 점선 화살표로 표현합니다.
- 의존 관계는 일시적이며, 한 클래스가 다른 클래스에 의존하지만 그 클래스의 구성요소는 아닙니다.
- 한 클래스의 변경이 다른 클래스에 영향을 줄 수 있습니다.
Dependency(의존관계)를 Java 소스로 구현하면 아래와 같습니다.
// Customer 클래스
public class Customer {
private ShoppingCart cart;
public void addToCart(Product product) {
cart.addProduct(product);
}
public void checkout() {
Order order = new Order(cart);
order.placeOrder();
}
}
// ShoppingCart 클래스
public class ShoppingCart {
private List<Product> products;
public void addProduct(Product product) {
products.add(product);
}
public Order createOrder() {
return new Order(this);
}
}
// Order 클래스
public class Order {
private List<Product> products;
public Order(ShoppingCart cart) {
this.products = new ArrayList<>(cart.getProducts());
}
public void placeOrder() {
// 주문 처리 로직
}
}
// Product 클래스
public class Product {
private String name;
private double price;
// 생성자, 게터/세터 메서드 등
}
1-2-5 Aggregation(집합)
집합관계는 하나의 객체와 하나의 객체를 구성하는 부분 객체들 간의 관계입니다.
- 전체 객체와 부분 객체의 관계를 나타냅니다.
- Link의 Dash 관계라고도 합니다.
- UML 다이어그램에서는 빈 마름모 끝의 실선으로 표현합니다.
- 전체 객체와 부분 객체의 생명주기가 독립적입니다.
- 전체 객체(Car)가 소멸되어도, 각 각의 부분 객체(Engine,Door,Tier,Body)는 존재할 수 있습니다.
Aggregation(집합관계)을 Java 코드로 표현하면 아래와 같습니다.
public class Car {
private Door door;
private Engine engine;
private Body body;
private Tire tire;
public Car(Door door, Engine engine, Body body, Tire tire) {
this.door = door;
this.engine = engine;
this.body = body;
this.tire = tire;
}
// Getter and Setter methods for the components
public Door getDoor() {
return door;
}
public Engine getEngine() {
return engine;
}
public Body getBody() {
return body;
}
public Tire getTire() {
return tire;
}
}
public class Door {
// Door class implementation
}
public class Engine {
// Engine class implementation
}
public class Body {
// Body class implementation
}
public class Tire {
// Tire class implementation
}
1-2-6 Composition(합성)
합성관계는 집합관계와 비슷할 수 있으나, 전체객체와 부분객체의 결합이 좀 더 강한 관계라고 할 수 있습니다.
- 전체 객체와 부분 객체의 관계를 나타냅니다.
- Link의 Solid 관계라고도 합니다.
- UML 다이어그램에서는 실선 끝의 검은 마름모로 표현합니다.
- 전체 객체와 부분 객체의 생명주기가 의존적입니다.
- 전체 객체(Human)이 소멸되면, 각 각의 부분 객체(Engine,Door,Tier,Body)도 존재할 수 없습니다.
Composition(합성관계)을 Java 코드로 나타내면 아래와 같이 표현할 수 있습니다.
// 인간 클래스
public class Human {
private String name;
private Kidney kidney;
private Heart heart;
private Liver liver;
public Human(String name) {
this.name = name;
this.kidney = new Kidney();
this.heart = new Heart();
this.liver = new Liver();
}
// 인간 관련 메서드들
}
// 장기기관 클래스
public abstract class Organ {
protected boolean healthy;
public abstract void function();
}
// 신장 클래스
public class Kidney extends Organ {
@Override
public void function() {
// 신장 기능 구현
}
}
// 심장 클래스
public class Heart extends Organ {
@Override
public void function() {
// 심장 기능 구현
}
}
// 간 클래스
public class Liver extends Organ {
@Override
public void function() {
// 간 기능 구현
}
}
이렇게 클래스 다이어그램에 대해서 알아봤습니다.
혹시라도 정정할 내용이나 추가적으로 필요하신 정보가 있다면 댓글 남겨주시면 감사하겠습니다.
오늘도 Jindory 블로그에 방문해주셔서 감사합니다.
[참조]
https://brownbears.tistory.com/577