공부 잡동사니/디자인 패턴
게임 프로그래밍 패턴 : [4] 프로토타입 패턴
gamzachips
2024. 9. 5. 16:32
원형이 되는 인스턴스를 사용하여 생성할 객체를 명시하고,
이렇게 만든 견본을 복사해서 새로운 객체를 생성한다.
예제1) 몬스터 스포너
몬스터 종류마다 스포너를 만들면
몬스터의 상속 구조와 스포너의 상속 구조가 같아진다.
이러면 반복되는 코드, 중복이 많아지게 된다.
-> 프로토 타입 패턴으로 해결
어떤 객체가 자기와 비슷한 객체를 스폰할 수 있다.
즉 어떤 몬스터 객체든 자신과 비슷한 몬스터 객체를 만드는 원형 객체로 사용할 수 있다.
class Monster
{
public:
virtual ~Monster();
virtual Monster* Clone() = 0;
};
class Ghost : public Monster
{
public:
Ghost(int _health, int _speed) : health(_health), speed(_speed) {}
virtual Monster* Clone()
{
return new Ghost(health, speed);
}
};
스포너 클래스는 여러 종류를 만들 필요 없이 Monster의 Clone 함수를 호출해주면 된다.
class Spanwer
{
public:
Spawner(Monster* _prototype) : prototype(_prototype) {}
Monser* SpawnMonster()
{
return prototype->Clone();
}
private:
Mosnter* prototype;
};
Monster* ghostPrototype = new Ghost(50, 3);
Spawner* ghostSpawner = new Spawner(ghostPrototype);
프로토타입 패턴은 클래스 뿐 아니라 상태독 ㅏㅌ이 복제한다는 점에서 유용하다.
하지만 Monster종류마다 클래스를 구현하고 Clone 함수를 작성해야 하므로 코드 양에는 거의 차이가 없다.
요즘은 이렇게 개체 종류별로 클래스를 만들기보다는 컴포넌트나 타입 객체로 모델링한다.
대체1) 스폰 함수
Monster* SpawnGhost() { return new Ghost();}
typedef Monster* (*SpawnCallback)();
class Spawner
{
public:
Spawner(SpawnCallback _spawn) : spawn(_spawn){}
Monster* SpawnMonster() {return spawn();}
private:
SpawnCallback spawn;
};
Spawner* ghostSpawner = new Spawner(spawnGhost);
몬스터 종류마다 스포너 클래스를 만드는 대신 스폰 함수를 만들어 넘긴다.
대체2) 템플릿
class Spawner
{
public:
virtual ~Spanwer(){}
virtual Monster* SpawnMonster() = 0;
};
template <typename T>
class SpawnerFor : public Spawner
{
public:
virtual Monster* SpawnMonster() { return new T(); }
};
Spanwer* ghostSpawner = new SpawnerFor<Ghost>();
몬스터 클래스를 템플릿 타입 매개변수로 전달하여 스포너를 만든다.