'게임 프로그래밍 패턴' 교재를 학습하며 핵심 내용과 함께 개인적으로 보충한 내용을 정리해보았다.
- 경량 패턴(Flyweight Pattern; 플라이급 패턴)이란?
- 한 개의 고유 상태를 다른 객체들에게 공유하여 메모리 사용을 줄이는 패턴이다.
- 생성 객체를 공유한다는 점에서 C++ 포인터와 같은 개념이다. - 언제, 왜 사용하는가?
- 공통적으로 어떤 객체의 개수가 너무 많아서 좀 더 가볍게 만들고 싶을 때 활용할 수 있다.
- 경량 패턴을 사용하면 객체를 마구 늘리지 않고도 객체지향방식의 장점을 취할 수 있으므로 열거형으로 수많은 다중 선택문(switch문)을 만들 때 대안으로 사용할 수 있다. - 경량 패턴에서의 객체 데이터 두 종류
1. 고유 상태(=자유 문맥) : 모든 객체의 데이터 값이 같아서 공유할 수 있는 데이터 ex. 나무 형태, 텍스처
2. 외부 상태 : 인스턴스 별로 값이 다른 데이터 ex. 나무의 위치, 크기, 색 - 구체적인 사용과 구현 예시
1. 공유 객체가 명확한 경우
- 게임 속에 수천 그루가 넘는 월드를 표현해야 할 때, 이 나무들은 공통적으로 다음과 같은 데이터를 가진다.
폴리곤 메시
텍스처
월드에서의 위치와 방향
크기와 음영 값을 조절할 수 있는 매개변수
- 이렇게 객체에 든 데이터 대부분이 인스턴스별로 다르지 않다면 같은 내용을 메모리에 중복하여 여러번 올릴 필요가 없다.
- 따라서 공유 객체인 TreeModel 객체 하나만 존재하게 하고 Tree 클래스에는 인스턴스별로 다른 상태값만 남긴 채 나머지는 공유객체를 참조하도록 구현하면 된다.
2. 공유 객체가 명확하지 않은 경우
- 타일 기반의 지형 정보를 구현할 때, 땅이 작은 타일들이 모여 있는 거대 격자이고 모든 타일이 지형 정보 중 하나로 덮여 있는 경우 지형 종류에는 다음과 같이 게임 플레이에 영향을 주는 속성이 들어 있다.
플레이어가 얼마나 빨리 이동할 수 있을지를 결정하는 이동 비용 값
강이나 바다처럼 보트로 건너갈 수 있는 곳인지 여부
렌더링 할 때 사용할 텍스처
- 이러한 데이터는 하나로 합쳐 캡슐화하는 것이 좋으므로 지형(Terrain) 클래스를 따로 만드는 것이 좋다. 이때 같은 Terrain 객체를 여러 곳에서 공유해서 쓰기 때문에 모든 메서드를 const로 만든다. 단, 이 경우 한 곳에서 값을 바꾸면 그 결과가 여러군데서 동시에 나타나게 된다.
- 또한 타일마다 Terrain 인스턴스를 하나씩 만드는 비용을 방지하기 위해서 타일의 위치와 같이 타일 객체마다 달라지는 내용을 제외해 모든 지형상태가 고유한 "자유문맥" 상태를 유지하도록 한다. 이렇게 하면 world 클래스 격자 멤버 변수에 열거형이나 terrain 객체 대신 terrain 객체의 포인터를 넣어 지형 종류가 같은 타일들은 모두 같은 terrain 인스턴스 포인터를 가진다.
- Terrain 인스턴스는 여러곳에서 사용되므로 동적 할당시 생명 주기 관리에 어려움이 있을 수 있기 때문에 World 클래스에 저장한다.
- World 클래스가 지형의 세부 정보와 커플링 되지 않으므로 타일 속성(지형 속성값)은 World 메서드 대신 Terrain 객체에서 바로 얻을 수 있다. - 경량 패턴의 단점? 경량 패턴 사용 시의 성능에 대해
- 지형 데이터를 포인터로 접근한다는 것은 간접 구조화를 한다는 뜻이므로 포인터를 따라가면 캐시 미스가 발생할 수 있어 성능이 조금 떨어질 수는 있다. 하지만 이는 객체가 메모리에 어떤 식으로 배치 되느냐에 따라 달라질 수 있으므로 성능이 우려 된다면 사전에 프로파일링을 먼저 해보는게 좋다. - 관련 자료
- 경량 객체를 미리 전부 만들고 싶지 않거나 어떤 경량 객체가 실제로 필요한지 예측할 수 없다면 필요할 때 만드는 것이 낫다.
- 공유 기능을 유지하고 싶을 땐 인스턴스 요청시 이전에 같은 걸 만들어 놓은 게 있는지를 확인하고 그것을 반환한다. 이 때는 객체 생성시 기본 객체의 존재 여부를 먼저 확인할 수 있도록 생성 코드를 인터페이스 밑으로 숨겨둔다. 이렇게 생성자를 숨기는 방식은 팩토리 메서드 패턴의 한 예이기도 하다.
- 이전에 만든 경량 패턴 객체를 반환하기 위해 이미 생성해 둔 객체를 찾을 수 있는 풀을 관리해야 하며 이때 객체(오브젝트) 풀 패턴이 유용하게 사용 된다.
- 상태 패턴 사용시 '상태' 객체에 멤버 변수가 하나도 없는 경우 경량 패턴을 사용하면 상태 인스턴스 하나를 여러 상태 기계에서 동시에 재사용할 수 있다.
'CS > 디자인패턴' 카테고리의 다른 글
관찰자 패턴(Observer Pattern) (0) | 2022.08.29 |
---|---|
2장. 명령 패턴(Command Pattern) (0) | 2022.08.23 |
1장. 도입 (0) | 2022.08.16 |