프로그래밍 일반/디자인 패턴

팩토리 패턴(Factory pattern)

지노윈 2019. 11. 17. 16:51
반응형

객체 생성을 대리하여 처리하는 것을 통칭하는 관용어로 팩토리라 부릅니다.

이것을 팩토리 패턴으로 부르는 사람도 있지만 엄밀히는 아닙니다.

 

팩터리는 두 가지중 하나입니다.

  • 객체를 어떻게 생성하는지 알고 있는 "클래스"
  • 호출했을 때 객체를 생성하는 "함수"

팩터리 메서드

생성할 타입의 멤버 함수로 객체를 생성하여 리턴합니다. 이 메서드는 생성자를 대신합니다.

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;
}

 

[독서 리뷰] - 모던 C++ 디자인 패턴

 

모던 C++ 디자인 패턴

[객체 지향 프로그래밍/디자인 패턴] - 빌더 패턴(Builder Pattern) [분류 전체보기] - 디자인 패턴 [객체 지향 프로그래밍/디자인 패턴] - 팩토리 패턴(Factory pattern) [객체 지향 프로그래밍/디자인 패턴] -..

devjino.tistory.com

코드 참고 : https://cpp-design-patterns.readthedocs.io/en/latest/
 

Welcome to C++ Design Patterns’s documentation! — C++ Design Patterns 0.0.1 documentation

© Copyright 2018, Hans-J. Schmid Revision 786c83f8.

cpp-design-patterns.readthedocs.io