반응형
객체 생성을 대리하여 처리하는 것을 통칭하는 관용어로 팩토리라 부릅니다.
이것을 팩토리 패턴으로 부르는 사람도 있지만 엄밀히는 아닙니다.
팩터리는 두 가지중 하나입니다.
- 객체를 어떻게 생성하는지 알고 있는 "클래스"
- 호출했을 때 객체를 생성하는 "함수"
팩터리 메서드
생성할 타입의 멤버 함수로 객체를 생성하여 리턴합니다. 이 메서드는 생성자를 대신합니다.
static 함수로 직교좌표 Point와 극좌표 Point를 생성하는 코드입니다.
class Point
{
protected:
Point(const float x, const float y) : x{x}, y{y} {}
public:
float x, y;
static Point NewCartesian(float x, float y)
{
return{ x,y };
}
static Point NewPolar(float r, float theta)
{
return{ r*cos(theta), r*sin(theta) };
}
};
팩터리
별도의 클래스로 목적하는 객체의 생성 방법을 알고 있습니다.
Point 생성자 private로 선언하여 직접 생성하지 않도록 하였습니다.
PointFactory에서 생성하며 Point 생성자를 사용할 수 있도록 Ponit의 friend로 선언하였습니다.
class Point
{
public:
float x, y;
friend class PointFactory;
private:
Point(float x, float y) : x(x), y(y){}
};
class PointFactory
{
static Point NewCartesian(float x, float y)
{
return Point{ x,y };
}
static Point NewPolar(float r, float theta)
{
return Point{ r*cos(theta), r*sin(theta) };
}
};
추상 팩터리
이름이 암시하듯이 추상 클래스로 팩토리를 구현합니다.
추상 팩터리는 어떤 타입 하나가 아니라 여러 타입의 패밀리를 생성할 때 사용합니다.
struct HotDrink
{
virtual void prepare(int volume) = 0;
};
struct Tea : HotDrink
{
void prepare(int volume) override
{
cout << "Take tea bag, boil water, pour " << volume << "ml, add some lemon" << endl;
}
};
struct Coffee : HotDrink
{
void prepare(int volume) override
{
cout << "Grind some beans, boil water, pour " << volume << "ml, add cream, enjoy!" << endl;
}
};
struct HotDrinkFactory
{
virtual unique_ptr<HotDrink> make() const = 0;
};
struct CoffeeFactory : HotDrinkFactory
{
unique_ptr<HotDrink> make() const override
{
return make_unique<Coffee>();
}
};
struct TeaFactory : HotDrinkFactory
{
unique_ptr<HotDrink> make() const override {
return make_unique<Tea>();
}
};
class DrinkFactory
{
map<string, unique_ptr<HotDrinkFactory>> hot_factories;
public:
DrinkFactory()
{
hot_factories["coffee"] = make_unique<CoffeeFactory>();
hot_factories["tea"] = make_unique<TeaFactory>();
}
unique_ptr<HotDrink> make_drink(const string& name, int volume)
{
auto drink = hot_factories[name]->make();
drink->prepare(volume);
return drink;
}
};
int main()
{
DrinkFactory df;
df.make_drink("coffee", 200);
return 0;
}
함수형 팩터리
std::function에 객체를 생성하는 함수를 저장하여 호출합니다.
class DrinkWithVolumeFactory
{
map<string, function<unique_ptr<HotDrink>()>> factories;
public:
DrinkWithVolumeFactory()
{
factories["tea"] = [] {
auto tea = make_unique<Tea>();
tea->prepare(200);
return tea;
};
}
unique_ptr<HotDrink> make_drink(const string& name);
};
inline unique_ptr<HotDrink> DrinkWithVolumeFactory::make_drink(const string& name)
{
return factories[name]();
}
GoF에서 설명하는 팩토리 메서드 패턴과 추상 팩토리 패턴을 알아 보겠습니다.
팩토리 메서드 패턴(Factory Method)
상속으로 구현하며, 어떤 객체를 만들 것인지를 서브클래스의 메서드가 결정합니다.
// Product
class Character
{
public:
virtual void Attack() = 0;
};
class Archer : public Character
{
void Attack() override
{
cout << "활을 쏜다.";
}
};
class Warrior : public Character
{
void Attack() override
{
cout << "검을 휘두른다.";
}
};
// Creator
class CharacterCreator
{
public:
Character* Create()
{
return FactoryMethod();
}
virtual Character* FactoryMethod() = 0;
};
class ArcherCreator : public CharacterCreator
{
// 다음과 같이 서브클래스의 메서드에서 만들 객체를 결정하기에 "팩토리 메서드 패턴"이란 칭한다.
Character* FactoryMethod() override
{
return new Archer;
}
};
class WarriorCreator : public CharacterCreator
{
Character* FactoryMethod() override
{
return new Warrior;
}
};
int main()
{
ArcherCreator* archer = new ArcherCreator();
Character* character = archer->Create();
character->Attack();
return 0;
}
추상 팩토리(Abstract Factory)
구성(Composition)으로 구현하며, 어떤 객체를 만들지는 추상 인터페이스의 구현으로 결정합니다.
class Weapon
{
public:
virtual int Power() = 0;
};
class Bow : public Weapon
{
int Power() override
{
return 200;
}
};
class Sword : public Weapon
{
int Power() override
{
return 50;
}
};
class Armor
{
virtual int Defence() = 0;
};
class Leather : public Armor
{
int Defence() override
{
return 50;
}
};
class Plate : public Armor
{
int Defence() override
{
return 200;
}
};
class EquipmentAbstractFactory
{
public:
virtual Weapon* CreateWeapon() = 0;
virtual Armor* CreateArmor() = 0;
};
// 다음과 같이 인터페이스 구현으로 어떤 객체를 만들지 결정합니다.
class ArcherEquipment : public EquipmentAbstractFactory
{
Weapon* CreateWeapon() override
{
return new Bow();
}
Armor* CreateArmor() override
{
return new Leather();
}
};
class WarriorEquipment : public EquipmentAbstractFactory
{
Weapon* CreateWeapon() override
{
return new Sword();
}
Armor* CreateArmor() override
{
return new Plate();
}
};
class Character
{
public:
Character(EquipmentAbstractFactory* equipment)
{
mWeapon = equipment->CreateWeapon();
mArmor = equipment->CreateArmor();
}
virtual void Attack() = 0;
protected:
// 구성으로 객체를 생성합니다.
Weapon* mWeapon;
Armor* mArmor;
};
class Archer : public Character
{
public:
Archer(EquipmentAbstractFactory* equipment) : Character(equipment) {}
void Attack() override
{
printf("활을 쏘아서 %d 공격을합니다.\n", mWeapon->Power());
}
};
class Warrior : public Character
{
public:
Warrior(EquipmentAbstractFactory* equipment) : Character(equipment) {}
void Attack() override
{
printf("검을 휘둘러서 %d 공격을합니다.\n", mWeapon->Power());
}
};
int main()
{
Character* archer = new Archer(new ArcherEquipment());
Character* warrior = new Warrior(new WarriorEquipment());
archer->Attack();
warrior->Attack();
return 0;
}
코드 참고 : https://cpp-design-patterns.readthedocs.io/en/latest/
'프로그래밍 일반 > 디자인 패턴' 카테고리의 다른 글
브릿지 패턴(Bridge Pattern) (0) | 2019.12.08 |
---|---|
어댑터 패턴(Adapter Pattern) (0) | 2019.12.08 |
싱글턴 패턴(Singleton Pattern) (0) | 2019.12.08 |
프로토타입 패턴(Prototype Pattern) (0) | 2019.12.08 |
빌더 패턴(Builder Pattern) (0) | 2019.11.17 |