추상 팩토리 클래스 로써,
객체의 생성을 독립적으로, 일관되게 처리하며 그 구현을 감출 때 사용한다.
코드를 보자.
#include <stdio.h> #include <stdlib.h>
enum ERACE_TYPE { ERACE_WARRIER, ERACE_MAGICION, ERACE_HEALER, MAX_RACE, };
class CRace // 종족 최상위 class. { // 기본적으로 종족들이 해야 할 interface를 정의한다. public: virtual ~CRace() = 0; virtual void Render() = 0; }; CRace::~CRace() {}
// 각 종족들에 대한 실 구현 코드. class CMan_Warrier : public CRace { public: void Render() { printf("Man_Warrier Rendered..\n"); } }; class CMan_Magicion : public CRace { public: void Render() { printf("Man_Magicion Rendered..\n");} }; class CMan_Healer : public CRace { public: void Render() { printf("Man_Healer Rendered..\n"); } };
class COak_Warrier : public CRace { public: void Render() { printf("Oak_Warrier Rendered..\n"); } }; class COak_Magicion : public CRace { public: void Render() { printf("Oak_Magicion Rendered..\n");} }; class COak_Healer : public CRace { public: void Render() { printf("Oak_Healer Rendered..\n"); } };
class CRaceFactory // 종족 생성 팩토리 class. { public: virtual CRace* CreateRace(ERACE_TYPE nType) = 0; };
// 각 종족에 대한 생성 팩토리 class. class CManRaceFactory : public CRaceFactory { public: CRace* CreateRace(ERACE_TYPE nType) { switch(nType) { case ERACE_WARRIER: return new CMan_Warrier; case ERACE_MAGICION:return new CMan_Magicion; case ERACE_HEALER: return new CMan_Healer; default: return 0; } } };
class COakRaceFactory : public CRaceFactory { public: CRace* CreateRace(ERACE_TYPE nType) { switch(nType) { case ERACE_WARRIER: return new COak_Warrier; case ERACE_MAGICION:return new COak_Magicion; case ERACE_HEALER: return new COak_Healer; default: return 0; } } };
void main() { CRaceFactory* pRaceFactory;
// 1. 사람 종족을 만들때. // 첫 생성시만 신경쓰면, 앞으로 계속 신경 쓸 필요 없다. ! //pRaceFactory = new CManRaceFactory; // 2. 오크 종족을 만들때. pRaceFactory = new COakRaceFactory;
CRace* pMans[MAX_RACE]; int k; for(k = 0; k < MAX_RACE; ++k) // 생성 인터페이스 통일. { pMans[k] = pRaceFactory->CreateRace((ERACE_TYPE)k); }
for(k = 0; k < MAX_RACE; ++k) // 업데이트 및 렌더 인터페이스 통일. { pMans[k]->Render(); }
for(k = 0; k < MAX_RACE; ++k) { delete pMans[k]; }
delete pRaceFactory;
}
이 방법을 사용하면 생성에 대해 가상으로 처리가 되어 hidden 처리 되고, 각 객체별 동일한 interface사용으로 개별적 구분의 필요가 사라지지만,
종족의 추가가 발생할 경우, createRace()함수 변경이 불가피 해 진다.
따라서 아래 clone() 방법을 사용한다.
class CRace // 종족 최상위 class. { // 기본적으로 종족들이 해야 할 interface를 정의한다. public: virtual ~CRace() = 0; virtual CRace* Clone() = 0; /// -> 추가된 함수 !!! virtual void Render() = 0; }; CRace::~CRace() {}
// 각 종족들에 대한 실 구현 코드. class CMan_Warrier : public CRace { public: CRace* Clone() { return new CMan_Warrier(*this); } void Render() { printf("Man_Warrier Rendered..\n"); } }; class CMan_Magicion : public CRace { public: CRace* Clone() { return new CMan_Magicion(*this); } void Render() { printf("Man_Magicion Rendered..\n");} }; class CMan_Healer : public CRace { public: CRace* Clone() { return new CMan_Healer(*this); } void Render() { printf("Man_Healer Rendered..\n"); } };
class COak_Warrier : public CRace { public: CRace* Clone() { return new COak_Warrier(*this); } void Render() { printf("Oak_Warrier Rendered..\n"); } }; class COak_Magicion : public CRace { public: CRace* Clone() { return new COak_Magicion(*this); } void Render() { printf("Oak_Magicion Rendered..\n");} }; class COak_Healer : public CRace { public: CRace* Clone() { return new COak_Healer(*this); } void Render() { printf("Oak_Healer Rendered..\n"); } };
class CRaceFactory // 종족 생성 팩토리 class. { public: virtual CRace* CreateRace(CRace* pRace) = 0; };
// 각 종족에 대한 생성 팩토리 class. class CManRaceFactory : public CRaceFactory { //----------------------------------------------------------// public: // !!! === 이 함수가 추가에 관계없이 구현이 고정된다. === !!! // CRace* CreateRace(CRace* pRace) { if(pRace) return pRace->Clone(); else return 0; } };
class COakRaceFactory : public CRaceFactory { public: CRace* CreateRace(CRace* pRace) { if(pRace) return pRace->Clone(); else return 0; } };
void main() { int k; CRaceFactory* pRaceFactory; CRace* pOrigine[MAX_RACE];
// 1. 사람 종족을 만들때. // 첫 생성시만 신경쓰면, 앞으로 계속 신경 쓸 필요 없다. //pRaceFactory = new CManRaceFactory; // --- 초기에 한번은 오리지날을 다 만들어 줘야 함. //pOrigine[ERACE_WARRIER] = new CMan_Warrier; //pOrigine[ERACE_MAGICION] = new CMan_Magicion; //pOrigine[ERACE_HEALER] = new CMan_Healer; // 2. 오크 종족을 만들때. pRaceFactory = new COakRaceFactory; pOrigine[ERACE_WARRIER] = new COak_Warrier; pOrigine[ERACE_MAGICION] = new COak_Magicion; pOrigine[ERACE_HEALER] = new COak_Healer;
CRace* pMans[MAX_RACE]; for(k = 0; k < MAX_RACE; ++k) // 생성 인터페이스 통일. { pMans[k] = pRaceFactory->CreateRace(pOrigine[k]); }
for(k = 0; k < MAX_RACE; ++k) // 업데이트 및 렌더 인터페이스 통일. { pMans[k]->Render(); }
for(k = 0; k < MAX_RACE; ++k) { delete pMans[k]; delete pOrigine[k]; }
delete pRaceFactory;
}
이 방법을 사용하면, 초기에 미리 객체를 만들어 두는 비용이 필요하지만,
대신 CreateRace()를 변경할 필요가 없어 진다.
결론적으로 아래와 같은 경우에 이 패턴은 유용하겠다.
1. 객체의 생성을 client가 직접 하는 것이 아니라, 간접적으로 수행함으로써 클라이언트가 객체의 생성이나 구성 또는 표현 방식에 독립적이고자 할때. 2. 여러 제품군 중 사용할 제품군을 쉽게 선택할 수 있도록 만들고 싶을 때. 3. 서로 관련된 제품들이 하나의 제품군을 형성하고, 이런 제품군이 여러개 존재하는 상황에서 생성되는 제품 객체가 항상 같은 제품군에 속하는 것을 확실히 보장하고 싶을 때. 4. 제품들에 대한 클래스 라이브러리를 만들어야 하는데, 그 인터페이스만 드러내고 구현은 숨기고 싶을 때.
이때, 각각의 인터페이스는 abstact factory class와 제품 종류별 abstract base class에 의해 외부에 드러나며, 구체적인 구현은 하위 클래스에 의해 이루어진다.
ㅇㅇ
|