추상 팩토리 패턴(Abstract Factory Pattern)

  • 추상 팩토리는 팩토리 메서드 패턴을 확장한 패턴입니다.
  • 팩토리 메서드 패턴은 객체 생성을 담당할 클래스를 인터페이스로 선언하여, 선언과 구현을 분리한 패턴입니다.

추상 팩토리 패턴의 구조

  • 추상 팩토리는 팩토리 메서드와 비슷한 성격을 갖고 있습니다. 한 가지 다른 점은 추상 팩토리는 추상화된 객체 생성을 그룹으로 관리합니다.
  • 추상 팩토리는 팩토리 메서드 패턴을 잘 이해하고 있다면, 쉽게 이해할 수 있습니다.

추상 팩토리 패턴: 인터페이스 클래스

  • 팩토리 메서드와 동일하게 객체 생성을 담당할 인터페이스 클래스를 선언합니다.
class IFactory
{
public:
    virtual std::shared_ptr<ITireProduct> createTire() = 0;
    virtual std::shared_ptr<IDoorProduct> createDoor() = 0;
};
  • 팩토리 메서드와는 다르게 인터페이스 클래스에 두 개의 가상 함수를 선언합니다.
  • ITireProduct를 생성할 createTire() 메서드와 IDoorProduct를 생성할 createDoor()를 선언합니다.

추상 팩토리 패턴: 인터페이스 구현

  • IFactory를 상속하는 자식 클래스를 구현합니다.
  • 인터페이스 클래스가 두 개의 객체 생성 메서드가 있으므로, 구현 클래스도 각각 구현하도록 합니다.
class KoreaFactory final :
    public IFactory
{
public:
    std::shared_ptr<ITireProduct> createTire() override
    {
        return std::make_shared<KoreaTireProduct>();
    }

    std::shared_ptr<IDoorProduct> createDoor() override
    {
        return std::make_shared<KoreaDoorProduct>();
    }

};

class StateFactory final :
    public IFactory
{
public:
    std::shared_ptr<ITireProduct> createTire() override
    {
        return std::make_shared<StateTireProduct>();
    }

    std::shared_ptr<IDoorProduct> createDoor() override
    {
        return std::make_shared<StateDoorProduct>();
    }
};
  • 이제 ITireProductIDoorProduct를 선언하고, 이를 상속하는 실제 클래스를 구현합니다.

추상 팩토리 패턴: 생성할 객체의 인터페이스 클래스

  • 이번에 생성할 객체의 그룹은 두 가지 입니다. (ITireProductIDoorProduct)
  • 두 객체의 인터페이스 클래스를 각각 선언합니다.
class ITireProduct
{
public:
    virtual void makeAssemble() = 0;
};

class IDoorProduct
{
public:
    virtual void makeAssemble() = 0;
};

추상 팩토리 패턴: 생성할 객체의 구현

  • ITireProductIDoorProduct을 상속하는 자식 클래스를 구현합니다.
  • 여기서 2개의 그룹과 2개의 추상 팩토리 객체가 존재하므로 총 4개의 자식 클래스가 필요합니다.
// KoreaFactory 클래스에서 생성할 클래스
class KoreaTireProduct final :
    public ITireProduct
{
public:
    void makeAssemble() override
    {
        std::cout << "Korea Tire is assembled" << std::endl;
    }
};

class KoreaDoorProduct final :
    public IDoorProduct
{
public:
    void makeAssemble() override
    {
        std::cout << "Korea Door is assembled" << std::endl;
    }
};

// StateFactory 클래스에서 생성할 클래스
class StateTireProduct final :
    public ITireProduct
{
public:
    void makeAssemble() override
    {
        std::cout << "State Tire is assembled" << std::endl;
    }
};

class StateDoorProduct final :
    public IDoorProduct
{
public:
    void makeAssemble() override
    {
        std::cout << "State Door is assembled" << std::endl;
    }
};

추상 팩토리 패턴: 실행 코드

  • 추상 팩토리 패턴의 동작 원리는 팩토리 메서드와 동일합니다.
  • 여기서 다른 점은 그룹으로 구분되는 점을 기억해야 합니다.
int main(const int argc, const char* argv[])
{
    // Korea Factory
    std::shared_ptr<IFactory> factory = std::make_shared<KoreaFactory>();
    std::shared_ptr<IDoorProduct> kDoor = factory->createDoor();
    kDoor->makeAssemble();

    std::shared_ptr<ITireProduct> kTire = factory->createTire();
    kTire->makeAssemble();

    std::cout << "\n\n" << std::endl;

    // USA Factory
    factory.reset(new StateFactory);
    std::shared_ptr<IDoorProduct> uDoor = factory->createDoor();
    uDoor->makeAssemble();

    std::shared_ptr<ITireProduct> uTire = factory->createTire();
    uTire->makeAssemble();

    return 0;
}
  • 추상 팩토리 객체를 생성하고, createDoor()createTire() 메서드를 호출하여 객체를 생성합니다.
  • kDoorkTire는 각각 std::shared_ptr<IDoorProduct>, std::shared_ptr<ITireProduct>으로 선언되었지만 추상 팩토리가 KoreaFactory으로 구체화 되었기 때문에 올바른 객체를 생성합니다.
  • 추상 팩토리는 클래스를 그룹으로 나눠서 복수의 객체를 생성하는데 편리한 장점이 있습니다.
  • 하지만 새로운 생성 객체를 추가한다면.. (예시: Engine) 변경 또는 추가되는 내용이 많다는 단점이 있습니다.
    • IFactory, KoreaFactory, StateFactory에 객체 생성 로직을 추가해야 합니다.
    • IEngine, KoreaEngine, StateEngine 클래스를 선언&구현해야 합니다.
    • 따라서 생성할 객체가 추가된다면 수정이 필요한 클래스가 매우 많습니다.