우선 코드부터 보자.
#include <iostream>
#include <vector>
#include <map>
#include "Helper.h"
class Shape
{
public:
virtual void draw() = 0;
virtual ~Shape() {}
virtual Shape* clone() = 0;
};
class Rect : public Shape
{
public:
void draw() override { std::cout << "draw Rect" << std::endl; }
Shape* clone() override { return new Rect(*this); }
static Shape* create() { return new Rect; }
};
class Circle : public Shape
{
public:
void draw() override { std::cout << "draw Circle" << std::endl; }
Shape* clone() override { return new Circle(*this); }
static Shape* create() { return new Circle; }
};
class ShapeFactory
{
MAKE_SINGLETON(ShapeFactory)
std::map<int, Shape*> prototype_map;
public:
void register_shape(int key, Shape* sample)
{
prototype_map[key] = sample;
}
Shape* create(int type)
{
Shape* p = nullptr;
auto it = prototype_map.find(type);
if (it != prototype_map.end())
{
p = it->second->clone();
}
return p;
}
};
int main()
{
std::vector<Shape*> v;
ShapeFactory& factory = ShapeFactory::get_instance();
Rect* redRect = new Rect;
Rect* blueRect = new Rect;
Circle* redCircle = new Circle;
factory.register_shape(1, redRect);
factory.register_shape(2, blueRect);
factory.register_shape(3, redCircle);
while (1)
{
int cmd;
std::cin >> cmd;
if (cmd >= 1 && cmd <= 7)
{
Shape* p = factory.create(cmd);
if (p)
v.push_back(p);
}
else if (cmd == 9)
{
for (int i = 0; i < v.size(); i++)
{
v[i]->draw();
}
}
}
}
객체들의 생성을 담당하는 Factory를 만든다.
공장에서 물건을 찍어내는 것이랑 비슷하다.
자동차 공장같은데서 "견본품 하나 주시면, 제가 똑같이 찍어 드리겠습니다" 이런느낌이다.
Shape는 draw()와 clone() 순수 가상 함수를 가지고 있고, Shape을 상속 받은 Rect와 Circle은
해당 함수를 override 한다.
그리고 ShapeFactory instance를 Singlton 구현방식으로 만들고, <= 즉 ShapeFactory 객체는 1개만 존재할 수 있다는 말
redRect, bluRect, red Circle 객체들을 만들어서 포인터 값을 Factory에 등록합니다.
Rect* redRect = new Rect; Rect* blueRect = new Rect; Circle* redCircle = new Circle; factory.register_shape(1, redRect); factory.register_shape(2, blueRect); factory.register_shape(3, redCircle); |
그러면 Factory에 해당 제품들이 등록이 된거고, 이제 마음대로 Factory에서 clone을 할 수 있다.
factory.create(1 or 2 or 3) 을 수행하면 redRect , blueRect, redCircle 제품을 계속 복제할 수 있는 것이다.
객체를 만드는 방법에 대해서 생각해보면 좋은데
- Rect rc => 자유롭지 못하고, 수명이 정해져있음. { } 를 벗어나게 되면 자연스럽게 파괴된다.
User가 원하는 시점에 파괴는 불가능하고, 전역변수로 정의한다면 파괴 안된다. - Rect rc = new Rect => 제일 자유로운 방법으로 User가 직접 메모리 할당, 해지 하는 시점을 정한다
자유롭게 할 수 있다는 것은 큰 장점이지만 꼭 "좋은 코드"라고 생각할 수는 없다.
만약 메모리 해지를 제대로 처리하지 않는다면 Memory leak가 생길 것이다. - Rect *rc = Rect::Create() => static 멤버 함수를 사용 , 이렇게 하면 다양한 제약을 걸 수 있는데
a. 오직 한 개만 만들 수 있게 해줘 => Singleton 기법으로 처리하면 된다 ( by 생성자를 private에 두면서)
b. 속성이 동일하면 공유한다. => Flyweight 기법을 사용하면 된다. map을 이용해서 이미 만들어진 instance인지 확인 후 instance를 생성 - Rect* rc2 = rc->clone() => 복사본을 사용한 객체 생성 (Prototype)
- Rect* rc = factory.create() => 공장을 통한 객체 생성
'Programming > c++ Design Pattern' 카테고리의 다른 글
[C++ Design Pattern] Visitor (1) | 2023.12.01 |
---|---|
[C++] Iterator (1) | 2023.12.01 |
[C++ Design Pattern] Flyweight (1) | 2023.11.30 |
[C++ Design Pattern] Adapter (0) | 2023.11.30 |
[C++ Design Pattern] Decorator (0) | 2023.11.29 |