객체지향 & 언리얼 설계

mingu Lee·2026년 1월 17일

CS

목록 보기
20/21

핵심 요약

  • 깊은 상속 계층은 변경 전파와 결합 증가로 취약 구조 발생 가능
  • 언리얼 권장 구조는 Actor + Component 중심 합성(Has-A) 기반 설계
  • 인터페이스는 “정체(Who)” 대신 “능력(What)” 기준 연결로 결합 완화 가능
  • 델리게이트는 이벤트 기반 통지로 의존성 역전 및 확장성 확보 가능
  • 서브시스템은 엔진 수명 관리 기반 전역 서비스 제공 방식 존재
  • Primary Data Asset 기반 데이터 중심 설계는 코드 수정 없이 콘텐츠 교체 가능

1. Composition over Inheritance

1.1 깊은 상속 계층의 리스크

  • 상속 계층 증가 시 수정 한 번으로 전체 파급
  • 다중 상속/다이아몬드 문제로 구조 복잡도 증가
  • 부모 클래스 비대화(Fat Base Class)로 불필요 기능 상속 부담 발생
  • Tight Coupling 증가로 유지보수 비용 상승

1.2 언리얼 해법: Actor & Component 구조

  • 권장 관계는 Is-A보다 Has-A 중심
  • Actor는 월드 존재 단위, Component는 기능 단위 역할 분리 구조
  • ACharacter 내부에도 이동/메쉬 등이 컴포넌트로 구성되어 있음

1.3 예시: “Swimming Warrior / Swimming Goblin” 모델

  • 상속 기반 접근 시 클래스 분기 폭발 문제 발생
  • 합성 기반 접근 시 USwimmingComponent 부착만으로 기능 공유
  • 기능 제거 시 코드 수정 없이 컴포넌트 제거로 대응

1.4 합성 장점

  • Plug & Play 형태 조립식 설계 가능
  • 런타임 중 기능 추가/제거
  • 기능 재사용성 증가 및 의존성 감소

1.5 사용 기준

  • 상속 사용 구간은 “절대 변하지 않는 공통 분모” 정의에 제한
  • 합성 사용 구간은 “언제든 추가/제거 가능한 기능” 중심 적용

2. Interfaces for Decoupling

2.1 핵심 관점: Who vs What

  • CastTo 중심 설계는 대상 정체를 알아야 하는 구조
  • 인터페이스 설계는 수행 가능 행위(능력)만 요구하는 구조

2.2 Cast 기반 강결합 문제

  • 특정 클래스 캐스팅은 강한 결합(Strong Coupling) 유발
  • 상호작용 대상 증가 시 분기문 폭증 문제 발생
  • 순환 의존 및 컴파일/유지보수 비용 증가

2.3 인터페이스의 역할

  • “이 기능을 제공한다”는 규격(약속) 정의
  • 호출자는 구현체 정체와 무관하게 동일 함수로 호출

2.4 호출 패턴 핵심

  • ImplementsInterface 체크 후 Execute_Interact 호출
  • 대상 타입 분기 제거로 확장성 증가

2.5 기대 효과

  • 새 상호작용 대상 추가 시 호출부 수정 최소화
  • 협업 시 “규격 제공 + 구현 분리” 방식으로 작업 분업 가능


3. Delegates & Observer Pattern

3.1 문제 상황: 이벤트 수신자 다수 존재

  • 사망 이벤트 하나에 UI/사운드/카메라/업적/게임모드 등 다수 반응 필요 상황 존재
  • 발행자가 모두 직접 호출 시 의존성 폭발 및 클래스 비대화 발생

3.2 델리게이트 기반 옵저버 구조

  • 발행자(Subject)는 “발생 통지”만 수행
  • 구독자(Observer)는 “구독 후 반응” 수행
  • 발행자는 구독자 존재 여부와 무관한 설계 가능

3.3 멀티캐스트 델리게이트 흐름

  • 발행자: DECLARE_DYNAMIC_MULTICAST_DELEGATE 선언 후 Broadcast() 호출
  • 구독자: AddDynamic 등으로 콜백 연결

3.4 기대 효과

  • 의존성 역전(발행자 → 구독자 직접 참조 제거)
  • 기능 추가 시 발행자 코드 수정 최소화
  • 이벤트 순서/생성 순서 문제 완화

4. Unreal Subsystems

4.1 싱글톤의 요구와 한계

  • 전역 접근 가능한 단일 서비스 필요 상황이 빈번하게 존재
  • 전통 싱글톤은 수명 관리/초기화 순서/테스트 어려움 문제 존재

4.2 서브시스템 핵심

  • 엔진이 생성/파괴를 관리하는 자동 수명 관리 구조
  • 범위(Scope) 단위로 서비스 분리 가능

4.3 대표 종류

  • EngineSubsystem: 엔진 전체 수명 범위 대상
  • GameInstanceSubsystem: 게임 실행 전체 범위 대상
  • WorldSubsystem: 월드(레벨) 범위 대상
  • LocalPlayerSubsystem: 로컬 플레이어 범위 대상

4.4 설계 이점

  • God Class 방지 및 SRP(단일 책임) 유지 가능
  • 기능별 독립 모듈화로 유지보수 효율 증가 가능
  • 어디서든 GetSubsystem<T> 접근으로 참조 탐색 비용 감소 가능

5. Data-Driven + Strategy Pattern

5.1 문제: 코드 수정 없는 콘텐츠 변경 요구

  • 스킬 데미지/이펙트/모션 변경 요구는 빈번하게 발생
  • 매번 코드 수정 및 빌드 필요 시 생산성 저하 발생

5.2 전략 패턴 핵심

  • 행동(알고리즘)을 별도로 캡슐화 후 교체 가능
  • Context는 전략을 실행, Strategy는 교체 대상 역할 분리 가능

5.3 언리얼 해법: Primary Data Asset

  • 수치/에셋/클래스 참조를 데이터로 분리
  • 에디터에서 데이터 교체로 콘텐츠 교체 가능
  • 기획/아트 작업자가 데이터 조정 가능 구조를 제공

5.4 기대 효과

  • 코드(시스템)와 데이터(콘텐츠) 분리로 유지보수 비용 감소 가능
  • 협업 분업 구조 강화 가능

결론: 유연성과 확장성 중심 설계 흐름

  • 합성으로 기능 조립
  • 인터페이스로 상호작용 결합 완화
  • 델리게이트로 이벤트 분리 및 확장성 확보
  • 서브시스템으로 전역 서비스 수명 관리
  • 데이터 에셋으로 콘텐츠 교체 및 협업 효율 증가
profile
Github: https://github.com/dlalsrn

0개의 댓글