.
1. 클래스 관계의 주요 유형
클래스 간의 관계는 크게 **연관(Association), 집합(Aggregation), 합성(Composition), 의존(Dependency), 상속(Inheritance), 구현(Implementation)**으로 나뉜다.
이제 각 관계를 상세히 살펴보자.
(1) 연관 관계 (Association)
연관 관계는 한 클래스가 다른 클래스를 참조하는 가장 일반적인 관계이다.
- 양방향 또는 단방향 연관이 가능하다.
- 클래스 간 독립성이 유지되며, 필요할 때 참조할 수 있다.
예제: 플레이어와 무기 관계
public class Player
{
public Weapon weapon; // Player가 Weapon을 참조 (단방향 연관)
}
public class Weapon
{
public string Name;
}
여기서 Player는 Weapon을 참조하지만, Weapon은 Player를 알지 못한다.
만약 양방향 연관을 원한다면, Weapon 클래스에서 Player를 참조하면 된다.
public class Weapon
{
public Player owner;
}
활용 사례 (Unity)
- Player ↔ Weapon (플레이어가 무기를 가짐)
- Enemy ↔ Target (적이 특정 대상을 공격함)
(2) 집합 관계 (Aggregation)
집합 관계는 연관 관계의 특수한 형태로, 한 클래스가 여러 개의 다른 객체를 포함하지만, 객체의 생명주기를 관리하지 않는 경우를 의미한다.
예제: 팀과 플레이어 관계
public class Team
{
public List<Player> players = new List<Player>();
}
- Team은 여러 개의 Player를 포함하지만, Team이 삭제되어도 Player 객체는 그대로 남는다.
- 즉, 개별 Player는 독립적으로 존재할 수 있다.
활용 사례 (Unity)
- Team ↔ Player (팀이 여러 플레이어를 포함)
- Inventory ↔ Item (인벤토리에 여러 아이템 포함)
(3) 합성 관계 (Composition)
합성 관계는 집합 관계와 비슷하지만, 한 클래스가 포함된 객체의 생명주기를 책임지는 경우를 의미한다.
즉, 부모 객체가 삭제되면 자식 객체도 삭제된다.
예제: 자동차와 엔진 관계
public class Engine
{
public void Start() => Console.WriteLine("엔진 가동!");
}
public class Car
{
private Engine engine = new Engine(); // Car가 Engine을 소유
public void StartCar()
{
engine.Start();
}
}
여기서 Car가 삭제되면 Engine도 삭제된다.
활용 사례 (Unity)
- Character ↔ HealthComponent (캐릭터가 체력 컴포넌트를 소유)
- Enemy ↔ AIController (적이 AI 컨트롤러를 소유)
(4) 의존 관계 (Dependency)
의존 관계는 한 클래스가 다른 클래스를 잠시 참조하는 관계를 의미한다.
즉, 메서드의 매개변수나 반환값으로 전달될 때 관계가 형성된다.
예제: 아이템 사용
public class Item
{
public string Name;
}
public class Player
{
public void UseItem(Item item)
{
Console.WriteLine($"{item.Name}을(를) 사용했습니다.");
}
}
- Player는 Item을 참조하지만, 일시적인 관계일 뿐, Item의 생명주기를 관리하지 않는다.
활용 사례 (Unity)
- Player ↔ Potion (플레이어가 포션을 사용)
- Weapon ↔ Enemy (무기가 적에게 데미지를 줌)
(5) 상속 관계 (Inheritance)
상속은 부모 클래스의 기능을 자식 클래스가 물려받는 관계이다.
C#에서는 :을 사용하여 상속을 표현한다.
예제: 캐릭터와 플레이어, 적 관계
public class Character
{
public int Health;
public void Move() => Console.WriteLine("이동 중...");
}
public class Player : Character
{
public void Attack() => Console.WriteLine("플레이어 공격!");
}
public class Enemy : Character
{
public void Roar() => Console.WriteLine("적이 포효함!");
}
- Player와 Enemy는 Character를 상속받아 공통 기능(Health, Move())을 공유한다.
- 상속을 사용할 경우 코드 중복을 줄일 수 있다.
활용 사례 (Unity)
- Character ↔ Player, Enemy (캐릭터를 상속)
- UIElement ↔ Button, Panel (UI 요소를 상속)
주의:
- 과도한 상속은 유지보수를 어렵게 만들 수 있음
- 상속 대신 인터페이스를 고려하는 것이 유리한 경우도 많음
(6) 인터페이스 구현 (Implementation)
인터페이스는 **구현해야 할 메서드나 속성을 강제하는 계약(Contract)**이다.
C#에서는 interface 키워드를 사용하며, 다중 구현이 가능하다.
예제: 상호작용 가능한 객체 만들기
public interface IInteractable
{
void Interact();
}
public class Door : IInteractable
{
public void Interact() => Console.WriteLine("문을 엽니다.");
}
public class NPC : IInteractable
{
public void Interact() => Console.WriteLine("NPC와 대화합니다.");
}
- IInteractable을 구현한 클래스는 반드시 Interact() 메서드를 제공해야 한다.
활용 사례 (Unity)
- IInteractable ↔ Door, NPC, Item (상호작용 가능한 객체)
- IDamageable ↔ Player, Enemy (데미지를 받을 수 있는 객체)
7. 클래스 관계 정리
| 관계 | 설명 | 예제 |
| 연관 (Association) | 한 클래스가 다른 클래스를 참조 | Player ↔ Weapon |
| 집합 (Aggregation) | 한 클래스가 여러 개의 객체를 포함하지만 생명주기를 관리하지 않음 | Inventory ↔ Item |
| 합성 (Composition) | 한 클래스가 포함된 객체의 생명주기를 책임짐 | Car ↔ Engine |
| 의존 (Dependency) | 일시적으로 참조하는 관계 | Player ↔ Potion |
| 상속 (Inheritance) | 부모 클래스를 자식 클래스가 확장 | Character ↔ Player, Enemy |
| 인터페이스 구현 (Implementation) | 클래스가 특정 동작을 보장해야 할 때 사용 | IInteractable ↔ NPC, Door |
8. 결론
클래스 간 관계를 잘 설계하면 코드의 유지보수성과 확장성이 극대화된다.
- **강한 결합(Composition) vs. 약한 결합(Aggregation, Dependency)**을 고려할 것
- 상속보다는 인터페이스와 조합(Composition)이 더 유리할 수도 있음
이제 실제 프로젝트에서 적절한 관계를 설계하여 클린 코드와 확장성 높은 구조를 만들어보자!
'소프트웨어 공학 > 코딩' 카테고리의 다른 글
| C#] 레코드(record)란? (0) | 2025.04.16 |
|---|---|
| Utility AI (0) | 2025.04.06 |
| C#] ReactiveProperty 및 ReactiveCollections 구현 (0) | 2025.03.13 |
| C#,유니티] 제네릭과 상속을 함께 사용하는 방법 (0) | 2025.03.11 |
| C#] 자식 클래스인지 판별하고 사용하는 방법들 (0) | 2025.03.10 |