1.디자인 패턴
디자인 패턴은 소프트웨어 설계 시 자주 마주치는 문제들을 효과적으로 해결하기 위해 검증된 재사용 가능한 설계 템플릿이야.
- 반복적으로 등장하는 설계 문제에 대한 모범 답안
- 코드 자체가 아니라 구조적인 해결 전략
- 이 상황엔 이렇게 설계하는 게 좋더라는 경험의 축적
1. 디자인 패턴이 필요한 이유
재사용성 향상 - 비슷한 문제에 반복적으로 사용 가능
유지보수성 강화 - 구조가 명확하여 디버깅이나 확장이 쉬움
의사소통 원활 - 팩토리 패턴 사용, 이라는 말 하나로 설계 의도를 공유할 수 있다.
코드 품질 향상 - 구조화된 코드로 실수가 줄어들고 확장에 유리함.
디자인 패턴은 무조건 써야 하는 법칙이 아니라, 상황에 따라 유용한 도구로
너무 남용하면 불필요한 복잡도만 생긴다.
하지만 잘 쓰면 코드의 유연성, 확장성, 가독성을 비약적으로 향상시킬 수 있는 장점이 있다.
2. 디자인 패턴의 분류
생성(Creational) - 객체를 생성하는 방식에 대한 패턴으로
- 싱글톤(Singleton), 팩토리 메소드(Factory Method), 빌더(Builder), 프로토타입(Prototype)
구조(Structural) - 클래스나 객체를 조합하여 더 큰 구조를 만드는 방식
- 어댑터(Adapter), 브릿지(Bridge), 복합체(Composite), 데코레이터(Decorator), 퍼사드(Facade)
행위(Behavioral) - 객체 간의 상호작용, 책임 분배
- 옵저버(Observer), 전략(Strategy), 커맨드(Command), 상태(State), 중재자(Mediator)
3. 싱글톤(Singleton) 패턴
- 단 하나의 인스턴스만 존재하게 하고, 그 인스턴스에 전역 접근을 허용하는 패턴
- 전역 변수와 비슷하지만, 캡슐화되어 있고, 지연 초기화(Lazy Initialization) 가능
GameManager, SoundManager, InputManager 등 전역적으로 단 하나만 필요한 시스템에 사용된다.
4. 옵저버(Observer) 패턴
- 한 객체의 상태 변화를 여러 객체가 자동으로 감지하고 반응하도록 만드는 패턴
Observer는 인터페이스(추상 클래스) 역할로, 상속한 클래스는 OnNotify를 구현해야 한다.
Subject는 옵저버들을 vector에 저장하고, 나중에 이벤트가 생기면 모든 옵저버에게 Notify를 보낸다.
UI 클래스는 Observer를 상속해서 OnNotify를 실제로 구현하여 UI가 이벤트에 반응 하도록 설계했다.
플레이어의 체력이 변화면 UI에 자동 반영하는데에 사용할 수 있다.
5. 상태(State) 패턴
객체의 상태에 따라 행동이 바뀌는 패턴
상태를 클래스로 분리하여, 상태 간 전이도 명확하게 구성한다.
상태(State)에 따라 객체가 캐릭터의 행동을 결정한다.
상태에 따라 Handle() 함수가 달라지고, 상태를 바꾼다.
애니메이션 상태 관리, AI 행동 전환, UI 상태 전환 등에 자주 쓰인다.
몬스터 AI(Idle, Patrol, Attack), 플레이어 상태(Idle, Run,Jump, Attack)
6. 커맨드(Command) 패턴
요청을 객체로 캡슐화하여 요청자와 실행자를 분리하는 디자인 패턴으로,
게임에서 자주 쓰이는 패턴이다.
키보드 입력에 따라 점프, 공격, 스킬사용 같은 동작을 캡슐화 하여 사용할 수 있다.
7. 전략(Strategy) 패턴
전략 패턴은 행동(알고리즘)을 캡슐화하여, 런타임에 교체할 수 있게 해주는 디자인 패턴으로
게임 개발에서는 걷기 <-> 날기, AI 전투 전략, 몬스터의 이동 방식 같은 것을 유연하게 바꿀 때 사용한다.
8. 팩토리(Factory) 패턴
팩토리 패턴은 객체 생성을 클래스 외부에서 통합적으로 관리하면서,
어떤 클래스인지 몰라도 객체를 생성할 수 있게 도와주는 디자인 패턴이다.
게임에서는 무기, 캐릭터, 몬스터, 아이템 등의 타입 문자열을 보고 간편하게 생성할 때 자주 쓰인다.
9. 컴포넌트 시스템(Component System)
컴포넌트 기반 아키텍쳐(Component-Based Architecture)
객체지향(OOP)보다 더 유연하게 게임 오브젝트를 조립하고 기능을 분리할 수 있게 해주며,
객체에 여러 기능 단위(Component)를 붙여 동작하게 한다.
Unity나 Unreal에서 사용되는 ECS(Entity Component System)의 기반이다.
2. 데이터 주도 설계(DOD : Date - Oriented Design)
데이터를 중심으로 설계하고, CPU가 데이터를 최적의 방식으로 처리할 수 있도록 구조화하는 설계
객체지향(OOP)은 코드의 구조와 재사용성을 중시하는 반면, DOD는 성능과 캐시 최적화를 중시한다.
CPU 캐시 효율을 높여 성능 향상과
연속된 메모리 구조로 빠른 순차 접근을 도와주고
최소한의 분기로 예측 가능한 처리가 가능하다.
해당 OOP 구조는 Enemy 객체 각각을 new로 생성하고, 포인터로 vector에 담는 방식으로
객체 하나하나가 힙에 흩어져 존재하여 캐시가 비효율적이다
DOD 방식은 모든 적들의 posX, posY, hp를 속성 단위로 분리해서 연속된 메모리 vector로 저장한다.
이 구조를 Structure of Arrays (SoA)라고 한다
이 방식을 각 속성마다 메모리가 연속적으로 구성되어 있어, 캐시 효율이 높아지고 CPU 성능을 극대화 할 수 있다.
또한 루프 내에서 posX[i], posY[i] 접근 시 캐시가 효율적으로 작동하며,
병렬 처리에도 유리하다.
실제 게임 개발에서는
작은 규모 게임은 객체 수가 적은 경우에 OOP로도 충분하지만
대규모 적 처리, 물리 계산, 파티클 등에서는 DOD 방식이 절대적으로 유리하다.
3. ECS(Entity Component System)
ECS란
DOD를 기반으로 만들어진 게임 아키텍쳐 패턴으로
게임 객체를 Entity, 그 속성을 Component, 로직을 System으로 분리한다.
Entity는 아무 데이터도 없는 고유 ID로 설정하고
Component에는 실제 데이터만을 가지는 구조체로 만들어준다.
System에서는 특정 컴포넌트를 가진 Entity들을 처리하는 로직이 된다.
1. ECS와 DOD의 장점
연속된 메모리로 컴포넌트들이 배열로 저장되어 캐시효율이 좋으며
분리된 데이터와 로직으로 한 시스템이 하나의 관심사만 처리한다.
컴포넌트 데이터끼이 독립적이기 때문에 병렬처리가 가능하여 멀티쓰레딩에도 적합한 장점이 있다.
또한 런타임에 엔티티에 컴포넌트를 추가/삭제가 가능하여 유연성도 뛰어나다.
'C++ Practice' 카테고리의 다른 글
생각나는데로 끄적어보는 c++ cs공부 (0) | 2025.03.31 |
---|---|
쓰레드(Thread) (0) | 2025.03.05 |
Study C++ Developer RoadMap (6) (0) | 2025.02.26 |
Study C++ Developer RoadMap (5) (0) | 2025.02.25 |
Study C++ Developer RoadMap (4) (0) | 2025.02.19 |