Simple Factory는 사실 디자인 패턴에 속하지 않는다. 하지만 프로그래밍을 하는데 있어서는 자주 사용되기도 하고, Factory Method 패턴이나 Abstract Factory 패턴과 많이 유사하기 때문에, '팩토리'의 대략적인 개념을 잡기위해 디자인 패턴 카테고리에 포함시켰다.


1. Simple Factory이란


Simple Factory는 객체를 생성하는 역할을 팩토리 클래스가 전담하게 하는 방법이다.


UML과 함께 보도록 하자.





Client - 객체의 생성을 요청하는 클래스

SimpleFactory - 객체의 생성을 담당하는 클래스

Product - 생성될 객체에 대한 인터페이스

ConcreteProduct1,2,3 - Product 인터페이스를 구현한 구상인터페이스


여기서 Client는 createProduct() 메소드를 통해 SimpleFactory에게 객체 생성을 전담하고 있다.

이렇게 하면 ConcreteProduct 객체들을 필요로하는 클래스가 여러개 있을 때, SimpleFactory 클래스를 통해 객체를 생성하기 때문에 ConcreteProduct 객체를 생성하는 부분에 대한 코드 중복을 방지 할 수 있다.



2. 적용 예제


Head First Desgin Pattern에 나오는 예제이다.


객체마을 피자가게에서는 클래스를 이용하여 판매하는 피자 종류를 관리하고, 피자를 주문받는다.

피자가게 관리를 위해서 다음의 클래스 구조를 이용하고 있었다.





우선 피자 인터페이와 구상 클래스 중 하나인 CheesePizza 클래스는 다음과 같이 정의된다.

<Pizza.h>

#pragma once #include <string> using namespace std; class Pizza { public: virtual void prepare() = 0; //피자의 재료를 준비한다. virtual void bake() = 0; //피자를 굽는다 virtual void cut() = 0; //피자를 자른다. virtual void box() = 0; //피자를 박스에 담는다. virtual string toString() = 0; //피자의 종류를 스트링으로 리턴한다. };

<CheesePizza.h>

#include <iostream> #include "Pizza.h" using namespace std; class CheesePizza : public Pizza { public: CheesePizza(); void prepare() override; void bake() override; void cut() override; void box() override; string toString() override; };


객체마을 피자가게를 나타내는 PizzaStore 클래스에서 피자를 주문하는 orderPizza 메소드는다음과 같이 구현된다.

Pizza* PizzaStore::orderPizza(string type){

Pizza pizza;


//피자 객체 생성

if(type.compare("cheese") == 0)

pizza = new CheesePizza();

else if(type.compare("greek") == 0)

pizza = new GreekPizza();

else if(type.compare("pepperoni") == 0)

pizza = new PepperoniPizza();


//피자 재료를 준비하고, 굽고, 자르고, 박스에 담아서 피자를 준비.

pizza.perpare();

pizza.bake();

pizza.cut();

pizza.box();

return pizza;

}


여기서 조개피자(Clam Pizza)와 야채피자(Veggi Pizza)가 

추가되고, 잘 팔리지 않는 그리스식 피자(Greek Pizza)가 제외된다고 하자 그러면 코드는 다음과 같이 수정된다.


Pizza* PizzaStore::orderPizza(string type){

Pizza pizza;


//피자 객체 생성

//바뀌는 부분

if(type.compare("cheese") == 0)

pizza = new CheesePizza();

else if(type.compare("greek") == 0)

pizza = new GreekPizza();

else if(type.compare("pepperoni") == 0)

pizza = new PepperoniPizza();

else if(type.compare("clam") == 0)

pizza = new ClamPizza();

else if(type.compare("veggi") == 0)

pizza = new VeggiPizza();


//피자 재료를 준비하고, 굽고, 자르고, 박스에 담아서 피자를 준비.

//바뀌지 않는 부분

pizza.perpare();

pizza.bake();

pizza.cut();

pizza.box();

return pizza;

}


orderPizza() 메소드에서 가장 문제가 되는 점은 판매하는 피자의 종류가 바뀔 때 마다 코드를 수정해야 한다는 점이다.

즉, 피자 객체를 생성하는 부분은 바뀌는 부분이다.


이제 바뀌는 부분을 알아냈으니 이 부분을 캡슐화 하면 된다.


바뀌는 부분인 객체를 생성하는 부분을 캡슐화 하기 위해서 팩토리 패턴을 적용하여 다음과 같은 구조로 구현한다.




여기서 SimplePizzaFactory가 피자의 생성을 담당한다.


SimplePizzaFactory의 createPizza() 메소드는 다음과 같이 구현된다.

<SimplePizzaFactory.cpp>


Pizza* SimplePizzaFactory::createPizza(const string& type) { Pizza * pizza = NULL; if (type.compare("cheese") == 0) pizza = new CheesePizza(); else if (type.compare("pepperoni") == 0) pizza = new PepperoniPizza(); else if (type.compare("clam") == 0) pizza = new ClamPizza(); else if (type.compare("veggi") == 0) pizza = new VeggiPizza(); return pizza; }


이제 객체를 생성하는 역할을 SimplePizzaFactory에게 전담시켰으니 orderPizza() 메소드를 다음과 같이 수정한다.

<PizzaStore.cpp>


Pizza* PizzaStore::orderPizza(const string& type) {

//팩토리를 통해 피자 객체 생성

SimplePizzaFactory factory; Pizza* pizza = factory.createPizza(type);

//피자 재료를 준비하고, 굽고, 자르고, 박스에 담아서 피자를 준비. pizza->prepare(); pizza->bake(); pizza->cut(); pizza->box(); return pizza; }

이제 피자 객체의 생성을 SimplePizzaFactory 클래스가 전담하기 때문에, 또 다른 클래스가 피자 객체를 생성해야 하는 상황이 생긴다면 이 SimplePizzaFactory를 이용하면 된다.


구현된 프로젝트는 다음의 깃허브에서 확인 할 수 있다.

(https://github.com/InvincibleTyphoon/SimpleFactoryPattern)

책에서는 Java를 사용하지만, 개인적으로 C++을 더 선호하는 관계로, 구현은 C++로 했다.


3. Simple Factory의 장점

- 객체를 생성하는 부분을 한 클래스에 캡슐화함


Simple Factory의 장점은 이 한마디로 정리 될 수 있다.

객체를 생성하는 부분을 한 클래스에 캡슐화하면, 여러 클래스에서 어떤 클래스의 객체를 생성할 때, 그 클래스를 생성하는 코드 중복을 방지 할 수 있다.

가령 위의 예제에서 PizzaStore 클래스 뿐만 아니라, 피자에 대한 설명을 찾아서 활용하는 PizzaShopMenu 클래스, 피자를 준비 할 때 피자를 박스에 포장(box() 메소드 호출)한 후에 또 봉지에 싸서 포장해야하는 HomeDelivery 클래스가 추가되고, 피자의 메뉴에 변경이 발생하면 PizzaStore,PizzaShopMenu,HomeDelivery 세 클래스에서 피자 객체를 생성하는 부분을 수정해야하는 어려움이 있다.

하지만 객체 생성을 SimplePizzaFactory 클래스가 전담하면 SimplePizzaFactory 클래스만 수정하면 된다.


4. 레퍼런스

- Head First Design Pattern(O'REILLY media)

블로그 이미지

서기리보이

,