Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Factory Method Pattern

일반적인 상황

factory는 공장을 의미한다. 공장패턴? 이 패턴은 공장의 작동방식을 생각해보면 어렵잖게 이해할 수 있는 패턴이다. 소프트웨어 개발이 아닌 영역에도 널리 쓰이는 패턴이다.

공장은 필요한 자원과 설비를 갖추고 있으며, 이들 자원과 설비를 이용해서 특정한 객체를 생산할 수 있는 시설이다. 만약에 오토바이를 만드는 공장이라고 하면, 이 공장은 단일 브랜드의 오토바이만 생산해내지는 않을 것이다. 그렇게 공장을 설계할리도 없을 것이다. 분명히 다양한 다양한 용도의 오토바이를 생산해낼 수 있게끔 설계할 것이다

이렇게 해서 얻을 수 있는 잇점은 여러개의 비슷한 공정을 가지는 시설을 여러개 가지고 있을 필요가 없다는 점이 될 것이다. 스위치만을 이용해서 비교적 간단하게 다양한 제품을 생산할 수 있다. 이를 소프트웨어에 그대로 응용한게 factory:::method:::pattern(:12)이다.

 pattern

상황극

  • 문 : 그래요. 알았으니 factory pattern의 현실적 예를 좀 들어주세요. 아무래도 이해가 좀.
  • 답 : 어떤 제품을 만든다고 하면, 파생되는 제품이 있을거에요. 이 제품이 공장에서 만들어진다면, 파생되는 제품까지를 하나의 공장에서 생산해낼 수 있도록 해야 겠죠 ?
  • 문 : 그런가요 ?
  • 답 : 그렇죠. 파생 제품이라는게 동일한 자원과 설비를 필요로 할거잖아요. 공정만 약간 다른 식이죠. 그렇다면, 하나의 공장에서 여러개의 공정을 수행할 수 있도록 범용가능하게 만드는게 훨씬 이익이죠. 비슷한 공장을 2-3개씩 만들면 엄청난 낭비 아니겠어요 ?
  • 문 : 음 그렇겠군요. 오토바이 공장이라면, 오토바이에서 파생되는게 제품이 스쿠터, 소형, 중형, 중대형 그리고 목적에 따라 여러가지가 만들어진다고 했을 때 스위치 조작정도로 여러개의 제품을 생산해낼 수 있도록 한다 뭐 그런거네요 ?
  • 답 : 네 맞아요.
  • 문 : 음. 객체지향 프로그래밍으로 보자면 class motocycle 가 만들어지고, 여기에서 상속되어서 cycle200cc, cycle300cc, batcar, roadrunner 클래스가 생성되는 형태겠군요.
  • 답 : 네. 아주 좋은 예인거 같네요. 더불어 엔진,프레임,조립등의 메서드들을 가상함수로 만들어서 상속된 클래스에서 구현하도록 할 수 있겠죠. 또한 병렬처리하는데에도 유용하겠죠 ? 한라인에서는 cycle200cc를 만들고 다른 라인에서는 cycle300cc를 만드는 등으로 말이죠.
  • 문 : (약간 우쭐해졌음) factory fattern 이라는 것도 그리 어려운건 아니군요.
  • 답 : 네. 일상생활에서 흔히 경험할 수 있는 것들이에요. 이름을 붙이고 붙이지 않는게 그래서 중요하죠. 체계적으로 정리하고, 효율적으로 소통할 수 있도록 도와주니까요.
  • 문 : 그렇겠네요. factory fattern을 위해서 구구절절하게 설명하는 것보다. 패턴의 의미를 알고 있다면, 훨씬 간단하게 의사소통이 가능하겠군요.

활용

  • 팩토리 패턴은 툴킷이나 프레임워크의 라이브러리에서, 주어지는 인자에 따라서 다른 객체를 생성해서 넘겨주고자 할때 사용할 수 있다.

사용예

Image Reader를 위한 클래스를 만드는 경우를 생각해보자. 이 클래스는 여러가지 이미지를 읽을 수 있어야 할 것이다. 그렇다면, 이미지 타입을 인자로 받아들이고 해당 이미지를 처리할 수 있는 객체를 생성해서 리턴할 수 있을 것이다.
#include <iostream>
#include <stdio.h>

#define GIF 1
#define JPG 2 
#define PNG 3

using namespace std;

class ImageReader
{
	public:
		virtual void decode() = 0;
};

class GIFReader: public ImageReader
{
	public :
		void decode() {cout << "GifReader RUN" << endl;}
};

class JPGReader: public ImageReader
{
	public :
		void decode() {cout << "JPGReader RUN" << endl;}
};

class PNGReader: public ImageReader
{
	public :
		void decode() {cout << "PNGReader RUN" << endl;}
};

class ImageReaderFactory
{
	private:
		int ImageType;
	public:
		void setImageType(int type)
		{
			ImageType = type;
		}
		ImageReader* getImageReader(int type)
		{
			setImageType(type);
			switch(type)
			{
				case GIF:
					return new GIFReader();  
				case JPG:
					return new JPGReader();  
				case PNG:
					return new JPGReader();  
				default:
					break;
			}
		}
};

// 테스트용 Main 코드
int main(int argc, char **argv)
{
	ImageReaderFactory * myReaderFactory;
	ImageReader *myReader;

	myReaderFactory = new ImageReaderFactory;
	myReader = myReaderFactory->getImageReader(PNG);
	myReader->decode();
}