우리가 윈도우 바탕화면에서 파일들을 실행하면 각 파일의 확장자나 정보에 따라 각기 다른 프로그램이 실행이 됩니다. 이런 상황에서 생성돼야 할 객체는 그 파일에 대한 응용 프로그램과 그 파일에 대한 객체입니다. 응용 프로그램은 운영체제 혹은 explorer.exe 에서 생성이 돼야 하고 그 파일은 생성된 응용 프로그램에서 생성이 되어야 합니다.
간단히 구조를 보면 Application을 상속받는 각 Hwp, Ppt Application 객체를 통해 새로운 객체를 만드는 구조가 됩니다.
class Application {
virtual void NewDocument(char* pFileName) = 0;
};
class HwpApplication : public Application {
void NewDocument(char* pFileName) {
HwpDocument* hwp = new HwpDocument();
hwp->open(pFileName);
}
};
class PowerpointApplication : public Application {
void NewDocument(char* pFileName) {
PptDocuemnt* ppt = new PptDocument();
ppt->open(pFileName);
}
};
위 코드는 얼핏보면 괜찮아 보일 수 있지만 NewDocument에서는 파일 종류에 따라 다른 객체를 생성해주는 부분만 다르게 됩니다. 현재는 2개의 종류만 있지만 종류가 더 늘어날수록 이런 부분은 비효율적이게 됩니다.
이런 비효율적인 부분을 방지하기 위해서는 NewDocument가 구현되는 부분을 상위 클래스에서 해주면 됩니다. 이렇게 되면 각 하위 종류별 Application 클래스에서 각각 구현하던 부분과 수정의 용이성까지 챙겨갈 수 있습니다. 이를 위해서는 두 가지 방법이 있는데 첫 번째로는 Application에서 기존 NewDocument에서 파일 별 객체를 생성할 수 있는 createDocument 함수를 따로 만들어 호출해 사용하는 것입니다. createDocument 함수는 각 Application 클래스마다 다른 객체를 생성해야 하고 생성된 객체는 공통된 cNewDocument 함수에서 사용할 수 있어야 합니다. 결국 NewDocument는 상위 클래스에서 createDocuemnt는 하위 클래스에서 overridng 해서 구현이 되어야 합니다.
위에서 설명한 구조를 그려보면 아래와 같은 구조가 나오게 됩니다.
class Document {};
class HwpDocument : public Document {};
class PptDocuemnt : public Document {};
class Application {
virtual Document* createDocument() = 0;
void NewDocument(char* pFileName) {
Document* pDoc = createDocument();
pDoc->open(pFileName);
}
};
class HwpApplication : public Application {
Document* createDocument() { return new HwpDocuemnt; }
};
class PptApplication : public Application {
Document* createDocument() { return new PptDocuemnt; }
};
int main()
{
HwpApplication hwp;
hwp.NewDocument("test.hwp");
}
이렇게 최상위 클래스를 추상 클래스로 만들면 하위 클래스에서 생성되는 객체는 명확히 구분될 수 있다는 장점이 있지만 하위 클래스에서 무조건 구현을 해줘야 한다는 단점이 있습니다. 최상위 클래스를 상속받는 하위 클래스가 많아지게 된다면 이것 또한 번거로운 점이 될 수 있습니다. 상황에 따라서 최상위 클래스에서 처리를 해주는 게 나을 수 있습니다.
class Document {};
class HwpDocument : public Document {};
class PptDocuemnt : public Document {};
class AnotherDocuemnt : public Document {};
class Application {
virtual Document* createDocument(char* pFileName) {
QFileInfo fi(QString(pFileName));
QString ext = fi.suffix(); // qt에서 file의 확장자 구하는 구문
if ( ext == "hwp" ) { return new HwpDocument; }
else if ( ext == "ppt" ) { return new PptDocuemnt; }
else { return new AnotherDocument; }
}
void NewDocument(char* pFileName) {
Document* pDoc = createDocument(pFileName);
pDoc->open();
}
};
class HwpApplication : public Application { };
class PptApplication : public Application { };
class AnotherApplication : public Application { };
int main()
{
HwpApplication hwp;
hwp.NewDocument("test.hwp");
}
마지막으로 template을 이용해서도 객체를 생성해줄 수 있습니다. template에 인자로 생성될 Docuemnt를 직접 전달해주게 됩니다.
class Document {};
class HwpDocument : public Document {};
class PptDocuemnt : public Document {};
class Application {
virtual Document* createDocument() = 0;
void NewDocument(char* pFileName) {
Document* pDoc = createDocument();
pDoc->open(pFileName);
}
};
template<class DocType>
class TemplateApplication : public Application {
Document* createDocument() { return new DocType; }
};
int main()
{
TemplateApplication<HwpDocument> hwp;
hwp.NewDocument("test.hwp");
}
지금까지 소개한 패턴이 팩토리 메소드 입니다. 정확히 팩토리 메서드는 어떤 객체를 생성하는 함수입니다. 위에서 보면 createDocument가 팩토리 메서드라고 볼 수 있습니다. 팩토리 메서드는 상황에 따라 다른 객체를 생성할 때 사용하면 좋습니다. 생성될 객체는 각각의 하위 클래스에 의해 결정되고 객체의 종류가 늘어날 때마다 하위 클래스를 확장하게 됩니다.
'Programming > C++' 카테고리의 다른 글
C++ 싱글톤 패턴 (0) | 2021.05.09 |
---|---|
C++ 프로토 타입 패턴 (0) | 2021.05.08 |
C++ 빌더 패턴 (0) | 2021.05.02 |
C++ 추상 팩토리 패턴 (0) | 2021.05.02 |
C++ 상속(Inheritance) (0) | 2020.05.08 |