[SOLID] 01. 객체지향 모델링
객체지향 모델링(Object-Oriented Modeling, OOM)은 시스템을 객체라는 기본 단위로 나누고, 객체 간의 상호작용을 정의하여 문제를 분석하고 설계하는 방법이다. 모델링(Modeling)에 대한 설명과 UML과 UML다이어그램 중에 클래스 다이어그램 중심인 포스팅이다.
1. 모델링
컴퓨터 공학 및 소프트웨어 개발에서 모델링(Modeling)은 소프트웨어 시스템, 프로세스, 데이터 구조 등을 설계하고 표현하기 위해 구조화된 형태의 추상화
를 생성하는 작업이다. 이는 복잡한 소프트웨어를 명확히 이해하고 효과적으로 개발하며, 문제를 체계적으로 해결하기 위한 중요한 단계이다.
1-1. 모델링의 목적
1) 시각적 표현
소프트웨어 시스템을 다이어그램이나 도식으로 표현하여 복잡한 시스템을 명확히 이해
2) 효율적 설계
요구사항 분석을 바탕으로 구조를 미리 설계하여 개발 과정에서 발생할 수 있는 오류를 줄임
3) 의사소통
개발자, 디자이너, 비즈니스 이해관계자 간의 의사소통을 돕는 언어로 활용
4) 문제 해결
문제를 체계적으로 정의하고 솔루션을 설계하기 위해 활용
5) 재사용 및 확장 가능성
설계 단계에서 재사용 가능한 구조를 고려해 미래 확장을 용이하게 만듬
2. UML
시스템을 모델로 표현해주는 대표적인 모델링 언어로 Unified Modeling Language (UML)
이 있다. UML은 요구분석, 설계, 구현 등 개발 과정에서 개발자 사이의 의사 소통이 원활하게 이루어지도록 표준화한 통합 모델링 언어이다. UML은 객체지향 소프트웨어 개발에서 널리 사용되며, 시스템의 구조와 동작을 명확히 설계, 시각화, 문서화하기 위한 도구로 활용된다.
2-1. UML의 주요 특징
- 표준화: OMG(Object Management Group)에서 정의한 표준 모델링 언어
- 다양성: 시스템의 구조적, 동적 측면을 모두 표현 가능
- 도구 독립성: UML을 지원하는 다양한 소프트웨어 설계 도구에서 활용 가능
- 유연성: 소프트웨어 외에도 비즈니스 프로세스, 데이터베이스 설계 등 다양한 분야에 적용 가능
2-2. UML 다이어그램의 종류
UML2.0에선는 시스템의 `구조(Structure)와 동작(Behavior)을 표현해서 다이어그램을 제공하고 있다. UML은 크게 구조적 다이어그램과 행동적 다이어그램으로 나뉜다.
1) 구조적 다이어그램(Structure diagram)
시스템의 정적 측면을 표현하며, 주로 구성 요소와 관계를 나타낸다.
1.1) 클래스 다이어그램 (Class Diagram)
- 객체지향 시스템에서 클래스와 그들 간의 관계를 표현
- 클래스의 속성, 메서드, 상속, 종속 등을 정의
1.2) 객체 다이어그램 (Object Diagram)
- 클래스의 인스턴스(객체)를 구체적인 정보를 보여줌
1.3) 컴포넌트 다이어그램 (Component Diagram)
- 시스템의 컴포넌트(물리적 구성 요소(모듈, 라이브러리 등))간 관계를 나타냄
1.4) 배치 다이어그램 (Deployment Diagram)
- 소프트웨어의 실행 시스템의 물리(하드웨어 노드, 네트워크 등) 구조를 표현
1.5) 패키지 다이어그램 (Package Diagram)
- 클래스, 컴포넌트 등을 그룹화한 패키지로 구성하고 패키지들간의 관계를 표현
2) 행동적 다이어그램(Behavior diagram)
시스템의 동적인 측면과 동작을 표현하며, 시간적 흐름이나 상호작용을 나타낸다.
2-1) 활동 다이어그램 (Activity Diagram)
- 프로세스의 흐름(작업, 조건, 병렬 작업, 연산 수행 등)을 나타냄
2-2) 상태 머신 다이어그램 (State machine Diagram)
- 객체의 생명주기를 표현
- 객체의 상태와 상태 간 전이를 모델링
2-3) 유스케이스 다이어그램 (Use Case Diagram)
- 사용자(Actor)와 시스템의 행위를 표현(상호작용)
- 시스템의 주요 기능과 사용 사례를 표현
2-4) 시퀀스 다이어그램 (Sequence Diagram)
- 시간 흐름에 따른 객체 사이의 상호작용을 표현
2-5) 상호작용 개요 다이어그램 (Interaction overview Diagram)
- 여러 상호작용 다이어그램 사이의 제어 흐름을 표현
2-6) 커뮤니케이션 다이어그램 (Communication Diagram)
- 객체 간의 메시지 흐름을 중심으로 상호작용을 표현
2-7) 타이밍 다이어그램 (Timing Diagram)
- 시간에 따른 객체의 상태 변화를 표현
3. 클래스 다이어그램
클래스란? 동일한 속성
과 행위
를 수행하는 객체의 집합이다. 클래스 다이어그램(Class Diagram)은 객체지향 설계의 핵심 다이어그램 중 하나로, 시스템 내 클래스들 간의 구조와 관계를 시각적으로 표현한 UML(Unified Modeling Language) 다이어그램이다. 자바와 같은 객체지향 언어 기반으로 설계할 때, 클래스 다이어그램은 설계 단계에서 클래스의 속성, 메서드, 관계 등을 정의하는 데 중요한 역할을 한다.
3-1. 클래스 다이어그램의 구성 요소
1) 클래스 (Class)
- 정의: 객체를 생성하기 위한 틀(청사진)
- 표현 방식: 사각형으로 표현되며, 3개의 영역
- 클래스 이름: 클래스의 이름이 표시됨
- 속성(Attributes): 클래스의 상태를 나타내는 변수
- 메서드(Methods): 클래스의 동작(행동)을 나타내는 함수
2) 접근 제어자 (Access Modifiers)
- 속성과 메서드 앞에 표시되어 가시성을 정의
+
: Public (공개)-
: Private (비공개)#
: Protected (상속 관계에서만 접근 가능)~
: Default (같은 패키지 내에서 접근 가능)
3) 관계 (Relationships)
- 클래스들 간의 연관성을 나타냄
- 연관 (Association): 클래스 간에 서로 알고 있는 관계 (→)
- 집합 (Aggregation): 클래스가 다른 클래스의 일부로 포함되지만 독립적으로 존재 가능 (◇)
- 구성 (Composition): 클래스가 다른 클래스의 일부로 포함되고, 생명 주기가 포함된 클래스와 연결됨 (◆)
- 상속 (Inheritance): 부모 클래스와 자식 클래스 간의 관계 (▷)
- 의존 (Dependency): 한 클래스가 다른 클래스에 의존하는 관계 (—→)
3-2. 관계
관계 | 설명 | 특징 | 표기법 |
---|---|---|---|
연관 (Association) | 두 클래스 간에 서로 알고 있는 관계를 나타냄 | - 클래스 간 상호작용이 필요 - 단방향 또는 양방향 가능 | 실선 (→) |
일반화 (generalization) | 부모 클래스와 자식 클래스 간의 관계 (“IS-A” 관계) | - 자식 클래스는 부모 클래스의 속성과 메서드를 상속 - 다형성 지원 - JAVA에서는 상속(Inheritance) | 빈 삼각형 (▷) |
집합 (Aggregation) | “부분-전체” 관계로, 포함된 객체가 독립적으로 존재 가능 | - 약한 결합 관계 - 부분(Part)은 전체(Whole)와 생명 주기가 독립적 | 빈 마름모 (◇) |
구성 (Composition) | “부분-전체” 관계로, 포함된 객체의 생명 주기가 전체와 연결됨 | - 강한 결합 관계 - 전체가 삭제되면 부분도 삭제됨 | 채워진 마름모 (◆) |
의존 (Dependency) | 한 클래스가 다른 클래스가 제공하는 기능을 사용할 때 잠시 나타내는 약한 관계 | - 클래스 간 낮은 결합도 유지 - 일시적으로 메서드 매개변수 등으로 사용 | 점선 화살표 (—→) |
실체화 (Realization) | 인터페이스와 이를 구현하는 클래스 간의 관계 - 책임들의 집한인 인터페이스와 이 책임들을 실제로 실현한 클래스들 사이의 관계 | - 인터페이스에 정의된 메서드를 구현 - 인터페이스와 구현 클래스 간의 관계를 표현 | 점선 삼각형 (—▷) |
요약
- 연관: 단순 참조 관계
- 상속: 부모-자식 관계
- 집합: 독립적 부분-전체 관계
- 구성: 강한 부분-전체 관계
- 의존: 임시적 관계
- 실체화: 인터페이스와 구현 클래스 간 관계
① 연관 관계
단순한 형태의 Association Relationship은 클래스들이 서로 연관되어 있음을 나타낸다. 이를 더 쉽게 이해할 수 있도록 아래에 개념을 설명한다. Association(연관)은 두 클래스 간의 기본적인 관계입니다. 하나의 클래스가 다른 클래스와 “알고 있다” 또는 “연결되어 있다”는 의미를 가진다.
1) 단방향 관계 (Unidirectional Relationship)
한쪽 클래스만 다른 클래스를 참조하거나 알고 있는 관계로 관계 탐색이 한 방향으로만 이루어진다. 예시로 <학생(Student) → 수업(Class)> 학생은 자신이 수강하는 수업을 알고 있지만, 수업은 자신을 수강하는 학생들을 모른다.
Class A ---> Class B
//수업 클래스
class Class {
private final String className;
public Class(String className) {
this.className = className;
}
public String getClassName() {
return className;
}
}
//학생 클래스
class Student {
private String name;
private Class enrolledClass;
public Student(String name, Class enrolledClass) {
this.name = name;
this.enrolledClass = enrolledClass;
}
public void showClassInfo() {
System.out.println(name + " 학생은 " + enrolledClass.getClassName() + " 수업에 등록되어 있습니다.");
}
}
public class UnidirectionalRelationship {
public static void main(String[] args) {
Class classLecture = new Class("수학");
Student student = new Student("김철수", classLecture);
student.showClassInfo();
}
}
2) 양방향 관계 (Bidirectional Relationship)
두 클래스가 서로를 참조하거나 알고 있는 관계로 관계 탐색이 양방향으로 이루어진다. 두 클래스가 서로의 정보를 필요로 할 때 사용되며 예시로 <주문(Order) ↔ 고객(Customer)> 고객은 자신이 주문한 것을 알고, 주문은 자신을 주문한 고객들을 알고 있다.
Class A <--> Class B
//주문 클래스
class Order {
private String orderId;
private Customer customer;
public Order(String orderId, Customer customer) {
this.orderId = orderId;
this.customer = customer;
}
public String getOrderId() {
return orderId;
}
public Customer getCustomer() {
return customer;
}
}
//고객 클래스
class Customer {
private String name;
private List<Order> orders;
public Customer(String name) {
this.name = name;
this.orders = new ArrayList<>();
}
public void addOrder(Order order) {
orders.add(order);
}
public void showOrders() {
System.out.println(name + "의 주문 목록:");
for (Order order : orders) {
System.out.println(" - 주문 ID: " + order.getOrderId());
}
}
}
/**
* 양방향 관계
*/
public class BidirectionalRelationship {
public static void main(String[] args) {
Customer customer = new Customer("박웅석");
Order order1 = new Order("001", customer);
Order order2 = new Order("002", customer);
customer.addOrder(order1);
customer.addOrder(order2);
customer.showOrders();
}
}
3) 다대다 관계(Many-to-Many Relationship)
은행(Bank)과 고객(Customer)은 서로 다대다 관계를 가질 수 있다. 은행과 고객의 관계를 다대다 관계로 구현한 예제로 한 고객은 여러 은행에 계좌를 개설할 수 있고, 한 은행도 여러 고객을 가질 수 있다.
3-1) 단방향 다대다 (Unidirectional Many-to-Many)
고객은 자신이 거래하는 은행을 알고 있지만, 은행은 고객을 모름
+----------------+ +----------------+
| Customer | | Bank |
+----------------+ +----------------+
| - name | | - name |
| - banks: List | ------>| |
+----------------+ +----------------+
class Bank {
private String name;
public Bank(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Customer {
private String name;
private List<Bank> banks; // 고객이 거래하는 은행들
public Customer(String name) {
this.name = name;
this.banks = new ArrayList<>();
}
public void addBank(Bank bank) {
banks.add(bank); // 고객이 은행과 거래 시작
}
public void showBanks() {
System.out.println(name + " 고객이 거래하는 은행들:");
for (Bank bank : banks) {
System.out.println(" - " + bank.getName());
}
}
}
/**
* 단방향 다대다 관계
*/
public class UnidirectionalManyToMany {
public static void main(String[] args) {
Bank bank1 = new Bank("국민은행");
Bank bank2 = new Bank("신한은행");
Customer customer = new Customer("김철수");
customer.addBank(bank1);
customer.addBank(bank2);
customer.showBanks();
}
}
3-2) 양방향 다대다 (Bidirectional Many-to-Many)
고객은 자신이 거래하는 은행을 알고, 은행도 자신의 고객들을 알고 있는 구조
+-------------------+ +-------------------+
| Customer |<------>| Bank |
+-------------------+ +-------------------+
| - name | | - name |
| - banks: List | | - customers: List |
+-------------------+ +-------------------+
class Customer {
private String name;
private List<Bank> banks; // 고객이 거래하는 은행들
public Customer(String name) {
this.name = name;
this.banks = new ArrayList<>();
}
public String getName() {
return name;
}
public void addBank(Bank bank) {
banks.add(bank); // 고객이 은행과 거래 시작
bank.addCustomer(this); // 은행도 고객을 "알게 함"
}
public void showBanks() {
System.out.println(name + " 고객이 거래하는 은행들:");
for (Bank bank : banks) {
System.out.println(" - " + bank.getName());
}
}
}
class Bank {
private String name;
private List<Customer> customers; // 은행이 거래하는 고객들
public Bank(String name) {
this.name = name;
this.customers = new ArrayList<>();
}
public String getName() {
return name;
}
public void addCustomer(Customer customer) {
customers.add(customer); // 은행에 고객 추가
}
public void showCustomers() {
System.out.println(name + " 은행의 고객들:");
for (Customer customer : customers) {
System.out.println(" - " + customer.getName());
}
}
}
/**
* 양방향 다대다 관계
*/
public class BidirectionalManyToMany {
public static void main(String[] args) {
Bank bank1 = new Bank("국민은행");
Bank bank2 = new Bank("신한은행");
Customer customer1 = new Customer("김철수");
Customer customer2 = new Customer("이영희");
// 고객이 은행과 거래 시작
customer1.addBank(bank1);
customer1.addBank(bank2);
customer2.addBank(bank1);
// 출력 확인
customer1.showBanks();
bank1.showCustomers();
}
}
3-3) 연관 클래스 (Association Class)
연관 클래스를 이용한 다대다 관계는 두 클래스 사이에 중간 역할을 하는 클래스(연관 클래스)를 추가하여 관계를 명확히 하고, 추가적인 정보를 저장하거나 관리할 수 있도록 설계한다.
고객 ↔ 은행 관계를 연관 클래스인 Account가 중간에서 고객과 은행의 관계를 나타낸다. 결국은 Customer과 Bank은 N:N 관계로 테이블 구조에서도 연관테이블이 존재하는 구조이다.
+----------------+ +----------------+ +----------------+
| Customer | | Account | | Bank |
+----------------+ +----------------+ +----------------+
| - name | | - accountId | | - name |
| |<----->| - balance |<----->| |
| | | - openedDate | | |
+----------------+ +----------------+ +----------------+
// 고객 클래스
class Customer {
private String name;
private List<Account> accounts; // 고객의 계좌 목록
public Customer(String name) {
this.name = name;
this.accounts = new ArrayList<>();
}
public String getName() {
return name;
}
public void addAccount(Account account) {
accounts.add(account);
}
public void showAccounts() {
System.out.println(name + " 고객의 계좌:");
for (Account account : accounts) {
System.out.println(" - 계좌 번호: " + account.getAccountId() + ", 잔액: " + account.getBalance());
}
}
}
// 은행 클래스
class Bank {
private String name;
private List<Account> accounts; // 은행의 계좌 목록
public Bank(String name) {
this.name = name;
this.accounts = new ArrayList<>();
}
public String getName() {
return name;
}
public void addAccount(Account account) {
accounts.add(account);
}
public void showAccounts() {
System.out.println(name + " 은행의 계좌:");
for (Account account : accounts) {
System.out.println(" - 계좌 번호: " + account.getAccountId() + ", 고객: " + account.getCustomer().getName());
}
}
}
// 연관 클래스: Account (고객과 은행을 연결)
class Account {
private String accountId;
private double balance;
private Date openedDate;
private Customer customer; // 연관된 고객
private Bank bank; // 연관된 은행
public Account(String accountId, double balance, Customer customer, Bank bank) {
this.accountId = accountId;
this.balance = balance;
this.openedDate = new Date(); // 현재 날짜로 계좌 개설일 설정
this.customer = customer;
this.bank = bank;
// 관계 설정
customer.addAccount(this);
bank.addAccount(this);
}
public String getAccountId() {
return accountId;
}
public double getBalance() {
return balance;
}
public Customer getCustomer() {
return customer;
}
public Bank getBank() {
return bank;
}
}
/**
* 연관 클래스를 이용한 다대다 관계
*/
public class AssociationClassManyToMany {
public static void main(String[] args) {
// 은행 생성
Bank bank1 = new Bank("국민은행");
Bank bank2 = new Bank("신한은행");
// 고객 생성
Customer customer1 = new Customer("김철수");
Customer customer2 = new Customer("이영희");
// 계좌 생성 (연관 클래스 사용)
new Account("001", 1000.0, customer1, bank1);
new Account("002", 2000.0, customer1, bank2);
new Account("003", 1500.0, customer2, bank1);
// 출력 확인
customer1.showAccounts();
bank1.showAccounts();
}
}
② 일반화(상속) 관계
일반화 관계(Generalization Relationship)는 객체 지향 설계에서 부모 클래스(상위 클래스)와 자식 클래스(하위 클래스) 간의 “is-a” 관계를 나타냅니다. 그래서 일반화 관계를 상속 관계라고 한다. 일반화 관계
는 공통된 속성
과 동작(메서드)
을 상위 클래스에서 정의하고, 이를 하위 클래스가 상속받아 사용하는 관계이다. 하위 클래스는 상위 클래스의 모든 속성과 동작을 물려받으며(다형성), 필요에 따라 확장(override 또는 추가 정의)할 수 있다.
+---------------+
| Animal |
+---------------+
| - name |
| + eat() |
+---------------+
▲
|
+----------+----------+
| |
+-----------+ +------------+
| Dog | | Cat |
+-----------+ +------------+
| + bark() | | + meow() |
+-----------+ +------------+
// 상위 클래스
class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + " is eating.");
}
}
// 하위 클래스 1
class Dog extends Animal {
public Dog(String name) {
super(name);
}
public void bark() {
System.out.println(name + " is barking.");
}
}
// 하위 클래스 2
class Cat extends Animal {
public Cat(String name) {
super(name);
}
public void meow() {
System.out.println(name + " is meowing.");
}
}
/**
* 일반화 관계
*/
public class GeneralizationRelationship {
public static void main(String[] args) {
// 상위 클래스 타입으로 하위 클래스 참조
Animal dog = new Dog("콜라");
Animal cat = new Cat("사이다");
// 상위 클래스의 메서드 호출
dog.eat();
cat.eat();
// 하위 클래스의 메서드 호출
if (dog instanceof Dog) {
((Dog) dog).bark();
}
if (cat instanceof Cat) {
((Cat) cat).meow();
}
}
}
◼︎ 일반화(상속) 관계
와 연관(포함) 관계
의 차이
1) 연관 관계 (Association Relationship)
연관 관계
는 클래스 간의 포함(Composite)
를 표현하며, "has-a"
관계로 한 클래스가 다른 클래스를 소유하거나 참조하는 관계이다. UML 다이어그램에서는 직선으로 표현한다.
- 예:
- Car has an Engine (자동차는 엔진을 가지고 있다)
- Student has a LibraryCard (학생은 도서관 카드를 가지고 있다)
2) 일반화 관계 (Generalization Relationship)
일반화 관계
는 클래스 간의 상속(Inheritance)
관계를 표현하며, "is-a"
관계로 상위 클래스(부모 클래스)의 속성과 메서드를 하위 클래스(자식 클래스)가 상속받는 관계이다. UML 다이어그램에서는 빈 삼각형 화살표로 표현한다.
- 예:
- Dog is an Animal (강아지는 동물의 일종)
- Car is a Vehicle (자동차는 차량의 일종)
③ 집합 관계
집합 관계(Aggregation Relationship)는 “has-a
” 관계의 한 유형으로, 클래스 간의 전체(Whole)와 부분(Part) 간의 관계를 나타낸다. 전체와 부분은 느슨하게 연결되어 있으며, 부분 객체는 전체 객체가 사라져도 독립적으로 존재할 수 있다. 다중성으로 일반적으로 1:N 관계로 사용된다.
UML 클래스 다이어그램에서 빈 다이아몬드로 표시하며, Team은 전체(Whole)이고 Player는 부분(Part)으로 전체가 부분을 느슨하게 소유하는 관계
이다.
+---------+ +---------+
| Team |<>---------->| Player |
+---------+ +---------+
| - name | | - name |
+---------+ +---------+
// Player 클래스 (부분 객체)
class Player {
private String name;
public Player(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// Team 클래스 (전체 객체)
class Team {
private String name;
private List<Player> players; // 팀에 속한 선수들
public Team(String name) {
this.name = name;
this.players = new ArrayList<>();
}
public void addPlayer(Player player) {
players.add(player); // 선수 추가
}
public void showPlayers() {
System.out.println(name + " 팀의 선수 목록:");
for (Player player : players) {
System.out.println(" - " + player.getName());
}
}
}
/**
* 집합 관계
*/
public class AggregationRelationship {
public static void main(String[] args) {
// 선수 생성
Player player1 = new Player("김으장");
Player player2 = new Player("임수정");
// 팀 생성
Team team = new Team("FC 서울");
// 팀에 선수 추가
team.addPlayer(player1);
team.addPlayer(player2);
// 팀 정보 출력
team.showPlayers();
}
}
④ 구성 관계
구성 관계(Composition Relationship)는 객체 지향 설계에서 “has-a
“를 나타냅니다. 구성 관계는 집합 관계와 유사하지만, 구성 관계는 전체 객체가 부분 객체를 강하게 소유
하고 있는 형태이다. 이는 전체(Whole)가 존재하지 않으면 부분(Part)도 존재할 수 없는 관계를 의미한다.
UML 다이어그램에서 채워진 다이아몬드(●)로 표시되며, House는 전체(Whole)이고 Room은 부분(Part)이다.
+--------+ +--------+
| Hotel |●------------->| Room |
+--------+ +--------+
| - name | | - name |
+--------+ +--------+
// 객실 클래스 (부분 객체)
class Room {
private String name;
public Room(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// 호텔 클래스 (전체 객체)
class Hotel {
private String name;
private List<Room> rooms;
public Hotel(String name) {
this.name = name;
this.rooms = new ArrayList<>();
}
public void addRoom(String roomName) {
rooms.add(new Room(roomName)); // 호텔이 객실을 소유
}
public void showRooms() {
System.out.println(name + "의 객실 목록:");
for (Room room : rooms) {
System.out.println(" - " + room.getName());
}
}
}
/**
* 구성 관계
*/
public class CompositionRelationship {
public static void main(String[] args) {
// 호텔 생성
Hotel hotel = new Hotel("포포인츠호텔");
// 객실 추가
hotel.addRoom("711-싱글스탠다드");
hotel.addRoom("856-더블스탠다드");
hotel.showRooms();
}
}
◼︎ 집합관계와 구성관계
1) 집합 관계(Aggregation Relationship)
느슨한 결합
- 부분 객체는 전체 객체의 생명 주기와 독립적
- 전체 객체가 삭제되더라도 부분 객체는 삭제되지 않음
- 예)
- 팀이 해체되어도 개별 선수들은 여전히 존재할 수 있음
- 도서관이 없어져도 책은 여전히 존재할 수 있음
- “has-a” 관계의 특수화
- 연관 관계(Association Relationship)와 비슷하지만, 전체와 부분 간의 소유권이 강조
- UML 표현
- UML 클래스 다이어그램에서 빈 다이아몬드로 표시
- 다중성
- 일반적으로 1:N 관계로 표현되며, 전체 객체는 여러 부분 객체를 포함
2) 구성 관계(Composition Relationship)
강한 결합
- 부분 객체는 전체 객체의 생명 주기에 종속
- 전체 객체가 삭제되면 부분 객체도 삭제
- 예)
- 집이 파괴되면 방도 사라짐
- 자동차가 없어지면 엔진도 존재할 수 없음
- “has-a” 관계의 특수화
- 구성 관계는 집합 관계와 유사하지만, 소유권이 강하게 유지
- UML 표현
- UML 다이어그램에서 채워진 다이아몬드(●)로 표시
- 부분 객체의 독립성 없음
- 부분 객체는 전체 객체 없이 독립적으로 존재할 수 없음
⑤ 의존 관계
의존 관계(Dependency Relationship)는 객체 지향 설계에서 한 클래스가 다른 클래스에 의존하는 관계를 나타낸다. 이 관계는 “사용 관계”라고도 하며, 한 클래스가 다른 클래스의 변화에 영향을 받는 관계이다.
의존 관계는 UML에서 한 클래스가 다른 클래스에 의존적으로 사용하는 관계를 나타낸다. 한 클래스가 다른 클래스의 메서드를 호출하거나 객체를 생성하여
임시로 사용하는 관계
를 의미한다. 그래서 의존 관계는 클래스 간의 약한 결합(loose coupling)을 하고 있다.
• 의존 관계의 특징
1) 임시적 관계
- 의존 관계는 한 클래스가 다른 클래스의 객체나 메서드를 일시적으로 사용할 때 발생
- 관계가 지속적이지 않으며, 한 번의 호출이나 특정 작업이 끝나면 종료
2) 약한 결합
- 의존 대상 클래스의 생명 주기에 직접 영향을 미치지 않으며, 독립적으로 존재할 수 있음
3) 변화에 민감
- 의존 대상 클래스가 변경되면, 의존하는 클래스의 동작에도 영향을 줄 수 있음
UML 클래스 다이어그램에서 점선 화살표(—->)로 표현되며, 화살표는 의존하는 클래스에서 의존 대상 클래스를 가리킨다. Order(주문) 클래스는 고객 정보를 사용하여 주문을 처리하지만, Order
와 Customer
는 생명 주기를 공유하지 않는다.
+-----------------+ +----------------+
| Order |----->| Customer |
+-----------------+ +----------------+
| - id | | - name |
| + processOrder()| | + getName() |
+-----------------+ +----------------+
// Customer 클래스
class Customer {
private String name;
public Customer(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// Order 클래스
class Order {
private int id;
public Order(int id) {
this.id = id;
}
// Customer를 의존적으로 사용하는 메서드
public void processOrder(Customer customer) {
System.out.println("Processing order ID: " + id + " for customer: " + customer.getName());
}
}
/**
* 의존 관계
*/
public class DependencyRelationship {
public static void main(String[] args) {
// Customer 객체 생성
Customer customer = new Customer("송양해");
// Order 객체 생성
Order order = new Order(123);
// Order가 Customer를 의존적(임시)으로 사용
// 한 클래스가 다른 클래스의 객체나 메서드를 임시로 참조 하는 관계
order.processOrder(customer);
}
}
⑥ 실체화 관계
실체화 관계(Realization Relationship)는 UML에서 인터페이스(Interface)
와 이를 구현하는 클래스(Class)
또는 구성 요소(Component)
간의 관계를 나타낸다. 이는 인터페이스에서 정의한 책임
을 객체에서 처리해야 할 일이다. 즉, 구현체가 인터페이스에서 정의한 동작(method)을 구현(implement)
하도록 보장하는 관계이다. 그레서 인터페이스와 구현체 간의 “can-do
” 관계이다.
UML 다이어그램에서 실체화 관계를 명확히 표현하면 클래스 간의 의존성과 책임
을 쉽게 파악할 수 있다. 이를 통해 인터페이스의 정의와 구현을 분리하고, 객체 지향 설계의 핵심인 다형성과 유연성을 제공한다.
UML에서 점선 삼각형 화살표(-----▷)
로 <인터페이스>-----▷<클래스(구현체)>
로 표현한다. Vehicle(인터페이스)와 이를 구현하는 Car(클래스)와 Bike(클래스) UML 다이어그램이다.
+----------------+
| <<interface>> |
| Vehicle |
+----------------+
| + start() |
| + stop() |
+----------------+
▲
|
---------------------
| |
+----------+ +----------+
| Car | | Bike |
+----------+ +----------+
| + start()| | + start()|
| + stop() | | + stop() |
+----------+ +----------+
// 인터페이스 (Vehicle)
interface Vehicle {
//인터페이스에서 정의한 책임(메서드)
void start();
void stop();
}
// 구현 클래스 1 (Car)
// 인터페이스에서 정의한 메서드를 구현
class Car implements Vehicle {
@Override
public void start() {
System.out.println("Car is starting.");
}
@Override
public void stop() {
System.out.println("Car is stopping.");
}
}
// 구현 클래스 2 (Bike)
// 인터페이스에서 정의한 메서드를 구현
class Bike implements Vehicle {
@Override
public void start() {
System.out.println("Bike is starting.");
}
@Override
public void stop() {
System.out.println("Bike is stopping.");
}
}
// 메인 클래스
public class RealizationRelationship {
public static void main(String[] args) {
// Vehicle 타입으로 Car와 Bike 객체를 참조
Vehicle car = new Car();
Vehicle bike = new Bike();
//인터페이스에서 정의한 책임을 처리
car.start();
car.stop();
bike.start();
bike.stop();
}
}