팩토리 메서드 패턴(Factory Method Pattern)

  • 팩토리 메서드 패턴은 두 가지 패턴(팩토리 패턴, 템플릿 메서드 패턴)이 결합한 팩토리 확장 패턴입니다.
  • 추상화(Abstract)는 팩토리 메서드 패턴을 구현하는데 중요한 개념입니다.
  • 객체를 생성하는 팩토리와 객체의 대상이 되는 클래스를 각각 추상화합니다.

팩토리 메서드 패턴의 구조

  • 인터페이스 클래스(Interface Class)는 클래스의 정의만 존재하는 클래스입니다.
  • 클래스의 실제 구현은 인터페이스 클래스를 상속하는 세부 클래스에서 구현합니다.
  • 팩토리 메서드는 팩토리와 생성 클래스를 인터페이스로 구현합니다.

팩토리 메서드 패턴: 인터페이스 클래스

  • 팩토리 메서드 패턴의 인터페이스 클래스를 선언합니다.
  • 생성된 객체를 반환하는 create() 메서드를 작성합니다.
  • 구체적인 객체의 생성은 IFactory를 상속하는 다양한 구현 클래스에 위임합니다.
  • create() 메서드는 자식 클래스에서 오버라이딩을 하지 못하게 final 키워드를 추가합니다.
    • 오버라이딩(Overriding): 부모 클래스의 메서드를 자식 클래스가 재정의하는 것을 의미합니다.
  • 또한 자식 클래스에서만 사용이 가능하도록 protected 접근 제한자로 한정합니다.
  • 실제 구체적인 객체를 생성하기 위한 IProduct 인터페이스 클래스를 반환합니다.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class IFactory
{
public:
    virtual std::shared_ptr<IProduct> create() final
    {
        return this->createProduct();
    }

protected:
    virtual std::shared_ptr<IProduct> createProduct() = 0;
};

팩토리 메서드 패턴: 구현

  • 팩토리 메서드 인터페이스 클래스 IFactory를 상속받는 구체적인 구현 클래스를 작성합니다.
  • 예제로 LG와 Apple 노트북을 만드는 자식 클래스를 구현합니다.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 객체의 생성을 담당할 자식 클래스의 실제 구현
class LGFactory final :
    public IFactory
{
protected:
    std::shared_ptr<IProduct> createProduct() override
    {
        return std::make_shared<LGProduct>();
    }
};

// 객체의 생성을 담당할 자식 클래스의 실제 구현
class AppleFactory final :
    public IFactory
{
protected:
    std::shared_ptr<IProduct> createProduct() override
    {
        return std::make_shared<AppleProduct>();
    }
};

팩토리 메서드 패턴: 생성할 객체의 인터페이스 클래스

  • 대상 객체의 인터페이스 클래스는 간단합니다.
1
2
3
4
5
6
// 생성할 객체의 인터페이스 클래스
class IProduct
{
public:
    virtual void name() = 0;
};

팩토리 메서드 패턴: 생성할 객체의 구현

  • IProduct를 상속하는 자식 클래스를 구현합니다.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 실제 생성할 객체 클래스
class LGProduct final :
    public IProduct
{
public:
    void name() override
    {
        std::cout << "LG Gram laptop" << std::endl;
    }
};

// 실제 생성할 객체 클래스
class AppleProduct final :
    public IProduct
{
public:
    void name() override
    {
        std::cout << "Apple Macbook laptop" << std::endl;
    }
};

팩토리 메서드 패턴: 실행 코드

  • 팩토리 메서드 인터페이스 클래스로 팩토리 메서드 객체를 생성하지만, 생성할 객체를 반환하는 구체적인 팩토리 메서드 타입을 지정합니다.
  • 팩토리 메서드 인터페이스 클래스의 메서드는 IProduct를 반환하지만, 이를 호출하는 쪽에서 구체적인 클래스를 명시할 경우, 해당 클래스를 생성하여 반환합니다.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int main(const int argc, const char* argv[])
{
    std::shared_ptr<IFactory> factory = std::make_shared<AppleFactory>();
    std::shared_ptr<IProduct> apple = factory->create();
    apple->name();

    factory.reset(new LGFactory);
    std::shared_ptr<IProduct> lg = factory->create();
    lg->name();

    return 0;
}

팩토리 메서드의 템플릿 적용

  • 지금까지의 구조는 생성할 객체의 대상이 많아지면, IProduct를 상속하는 클래스를 만들어야 합니다.
  • 이렇게 되면 클래스의 갯수가 늘어나고, 관리해야 하는 클래스가 많아지는 단점이 있습니다.
  • IProduct를 상속하여 특별한 추가 메서드를 작성하는 경우가 아니라면, C++template을 사용하여 범용적인 객체 생성 클래스를 작성할수 있습니다.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
template<typename SProduct>
class SFactory final :
    public IFactory
{
protected:
    std::shared_ptr<SProduct> createProduct() override
    {
        return std::make_shared<SProduct>();
    }
};
  • 이러한 방법을 사용하면 템플릿에 지정되는 SProduct에 따라 코드를 자동으로 생성할수 있습니다.