위와 같은 구조를 생각해보자.
Police나 Doctor나 Teacher는 여러가지 직업중에 하나다. 직업의 수는 계속적으로 들어날 수 있다.
문제는 User 클래스에서 직업에 대한 정확한 정보를 알지 않더라도 해당 직업자에게 일을 시키고 싶은 것이다.
이런 경우에 있어서 simple Factory 패턴에서는 중간에 Factory 클래스를 구성한다. GetFactory( ) 멤버 함수를 통해서 원하는 직종은 언제든지 불러낼수 있도록 한다.
이런 경우에 있어서 가장 큰 문제는 User가 일일이 각각의 직종 클래스에 대한 제어법을 알수가 없다는 것이다.
문제는 각각 직종에 대한 제어법을 알았다고 하더라도... 내부적으로 멤버 변수로 각각의 클래스를 다 넣어주는 것은 무리라는 것이다. 1000개의 직종을 얻어낼려고 천개의 변수를 설정해야하고 각각에 대한 제어법 역시 일일이 배워야 한다면... 어찌되겠는가?
이런 문제를 해결하기 위해서 다음과 같은 생각을 할수 있다.
각 직종에 대한 제어 방법을 획일화 할수 없을까?
예를 들어서 "도둑 잡으시오"라는 말대신 직종을 알지 못하더라도.."일하시오" 라고 하면 되지 않겠는가?
공부를 시키고 싶다면 학생 객체를 얻어서 "일하시오"라고 하면 공부할것이다.
결국은 객체에게 공통적인 멤버 함수를 부여하는 것이다.
User가 직종 자체를 알 필요가 없으면 많은 내부 멤버 변수를 없어도 된다.
결국은 이런 개념이라고 보면 되겠다. 경찰에게 일을 시키는 것이 아니라, 직종이라는 가상의 클래스를 만들어서 가상 직종이라는 녀석에게 무조건 "일하시오"라고 말하는 것이다.
위에 두가지 사항을 고려해보면 결국 다음과 같은 결론에 이르게 된다.
- 가상의 클래스가 하나 더 있어야 한다.
- "일하시오"와 같은 기능은 직종 클래스가 가지거나, 직종에서 파생한 클래스가 가질수 있다.
위와 같이 Job이라는 클래스를 만든다. 그리고 자기 직종에 대한 정보를 담을수 있는 CString mJob를 내부 멤버 변수로 가진다. DoCommand( ) 멤버 함수이며 mJob를 리턴한다고 가정하자.
결국 mJob에 누군가 값을 넣어주면 된다. 그 누군가는 파생 클래스인 각각의 직종이 될 것이다.
모두 생성자에거 mJob를 구성한다고 생각해보자.
/////////////////////////////////////
class Teacher : public Job
{
// Methods
public:
Teacher(){mJob="Teacher입니다";};
~Teacher();
};
//////////////////////////
Factory 클래스는 GetFactory 멤버 변수를 통해서 추상 클래스인 Job의 포인터를 반환받습니다.
결국 추상 클래스인 Job에 대한 사용법만 알면 아주 쉽게 1000개 넘는 직종을 제어할수 있는 거죠!!
물론 100개중에 어떤 직종인지를 의미하는 정보를 아큐먼트로 넘겨주겠죠?
그냥 상상되는 코딩은 이렇게 되겠죠..
/////////////User에서 사용하기////////////////////////
Job *mJob;
mJob=Factory::GetFactory(1);//1이 Teacher를 의미하는 내부적인 아큐먼트라고 합시다.
CString mStr=mJob->DoCommand();// 직종에 상관없이 모두 DoCommand()로 제어가 된다.
그렇다면 Factory::GetFactory( )는 어떻게 구성이 될수 있을까요?
////////////////상상이 될수 있는 Factory 코딩의 일부/////////////////////
Job* Factory::GetFactory(int i){
switch(i){
case 1:
return (Job*) new Teacher();
break;
default:
break;
}
}
/////////////////////////////////////
와 유사하게 코딩이 될 것입니다.
이제 우리가 고민했던 부분을 다 해결했습니다. 하지만 몇가지 생각을 해볼꺼리가 있죠..
바로 모든 정보를 저런 패턴으로 구성할수 있을까? 그것은 아닙니다. 다음과 같은 규칙이 존재한다는 것을 어렴풋이 느낄수 있습니다.
1. 데이타의 유사성이 존재하는가?
데이타의 유사성이란 숫자들이라던가, 문자열 이라던가와 같이 다루고자 하는 정보 자체가 일정한 규칙성이 있느냐 하는것입니다. 그렇다면 위와 같이 simple Factory 패턴으로 작업할수 있을 가능성이 높습니다.
2. 기능의 유사성이 존재하는가?
기능의 유사성이란 위와 같이 일을 시킨다는 멤버 함수는 있듯이.. 다루고자 하는 것이 어떤 유사성있는 기능을 하는지 ... 그렇다면 역시 simple Factory 패턴으로 구성이 가능합니다.
데이타의 유사성은 일반적으로 추상 클래스에서 파생됩니다. 기능의 유사성은 일반적으로 인터페이스의 클래스에서 파생됩니다.
위의 경우에 Job는 추상 클래스보다는 인터페이스로 구축하는 것이 합리적이지만 문제는 CString mJob라는 데이타를 설정함으로써 기능의 유사성과 함께 데이타의 유사성을 같도록 코딩에서 접근한 경우입니다. 이런 경우는 추상 클래스로 구성해야 합니다. 즉 1과 2과 동시에 존재하면 추상 클래스로 구성한다.
[최종적인 다이어그램]
User2는 최종적으로 Factory를 내부적으로 사용하게 될 것이다. 내부적으로 사용된다는 말은 User가 내부적으로 사용하거나 내부 멤버변수로 존재한다고 말할수 있다. 또한 다른 의미로는 Factory에 의해서 지배구조를 가지게 된다.
합성관계(저는 개인적으로 지배구조라고도 칭하는데)는 User3의 경우만 표현을 해봤다. 결국 1000개의 직종이 아니라 2개의 클래스만 이해하면 되는 것이다.
물론 Factory는 내부적으로 1000개와 연결이 되겠지만, 제공되는 DLL이라고 생각하면 되겠다. 즉 코딩이 아주 능숙한 사람이 Facotry와 내부 각각 객체를 설계할 거다. 그러니 사용자는 복잡한 구조를 알지 않고 두개만으로 끝난다.
여기서 중요한 것은 참조가 된다는 것은 지배구조를 의미한다라는 개념이며, 결국 어떤 클래스의 독립성이 그 만큼 좁아지기도 한다. 독립성은 좁아지지만 기능은 강화된다.