[디자인 패턴] 추상 팩토리 패턴 (Abstract Factory Pattern)
Computer Sci./Design Pattern

[디자인 패턴] 추상 팩토리 패턴 (Abstract Factory Pattern)

지난 포스팅에서 디자인패턴에 대한 개관을 살펴보았다. 이번 포스팅부터는 디자인 패턴을 하나씩 자세하게 알아보려고 한다. 

가장 먼저 살펴볼 패턴은 추상 팩토리 패턴이다. 추상 팩토리 패턴은 객체 생성(Object Creational)과 관련된 패턴이다. 

추상 팩토리 패턴은 상세화된 서브 클래스를 정의하지 않고도 서로 관련성이 있거나 독립적인 여러 객체의 군을 생성하기 위한 인터페이스를 제공한다. 이름만 봐서는 팩토리 메서드 패턴과 비슷해 보이지만 추상 팩토리 패턴은 팩토리 메서드 패턴을 좀 더 캡슐화한 방식이라고 볼 수가 있다.

 

추상 팩토리는 주로 다음과 같은 경우에 사용한다.

  • 객체가 생성되거나 구성, 표현되는 방식과 무관하게 시스템을 독립적으로 만들고자 할 때
  • 여러 제품군 중 하나를 선택해서 시스템을 설정해야 하고 한 번 구성한 제품을 다른 것으로 대체할 수 있을 때
  • 관련된 제품 객체들이 함께 사용되도록 설계되었고, 이 부분에 대한 제약이 외부에도 지켜지도록 하고 싶을 때
  • 제품에 대한 클래스 라이브러리를 제공하고, 그들의 구현이 아닌 인터페이스를 노출 시키고 싶을 때

 

추상 팩토리의 구조는 아래 그림과 같다.

<GoF의 디자인 패턴> p134

 

  • AbstractFactory: 개념적 제품에 대한 객체를 생성하는 연산으로 인터페이스를 정의
  • ConcreteFactory: 구체적인 제품에 대한 객체를 생성하는 연산을 구현
  • AbstractProduct: 개념적 제품 객체에 대한 인터페이스를 정의
  • ConcreteProduct: 구체적으로 팩토리가 생성할 객체를 정의하고, AbstractProduct가 정의하는 인터페이스를 구현
  • Client: AbstractFactory와 AbstractProduct 클래스에 선언된 인터페이스를 사용

 

이 패턴의 협력 방법은 일반적으로 ConcreteFactory 클래스의 인스턴스 한 개가 런타임에 만들어지면, 이 구체 팩토리(concrete factory)는 어떤 특정 구현을 갖는 제품 객체를 생성한다. 이 때 서로 다른 제품 객체를 생성하려면 사용자는 서로 다른 구체 팩토리를 사용해야 한다. 그리고 AbstractFactory는 필요한 제품 객체를 생성하는 책임을 ConcreteFactory 서브 클래스에 위임한다.

 

추상 팩토리의 장점과 단점은 다음과 같이 생각해 볼 수 있다.

장점

  • 구체적인 클래스를 분리한다. 추상 팩토리 패턴을 쓰면 응용 프로그램이 생성할 객체의 클래스를 제어할 수 있다. 팩토리는 제품 객체를 생성하는 과정과 책임을 캡슐화 한 것이기 때문에, 구체적인 구현 클래스가 사용자에게서 분리된다. 일반 프로그램은 추상 인터페이스를 통해서만 인스턴스를 조작한다.
  • 제품군을 쉽게 대체할 수 있다. 구체 팩토리의 클래스는 응용프로그램에서 한 번만 나타나기 때문에 응용프로그램이 사용할 구체 팩토리를 변경하기는 쉽다. 또한, 구체 팩토리를 변경함으로써 응용프로그램은 서로 다른 제품을 사용할 수 있게 변경된다. 추상 팩토리는 필요한 모든 것을 생성하기 때문에 전체 제품군은 한 번에 변경이 가능하다.

단점

  • 새로운 종류의 제품을 제공하기 어렵다. 새롭게 생성되는 제품은 추상 팩토리가 생성할 수 있는 제품 집합에만 고정되어 있기 때문이다. 만약 새로운 종류의 제품이 등장하면 팩토리의 구현을 변경해야 한다. 이는 추상 팩토리와 모든 서브클래스의 변경을 가져온다. 

 

추상 팩토리 구현하는 방법에는 여러가지가 있다.

  1. 팩토리를 단일체로 정의한다.
    • 전형적으로 응용프로그램은 한 제품군에 대해 하나의 ConcreteFactory 인스턴스만 있으면 된다.
    • 그러므로 단일체(Singleton)로 구현하는 것이 바람직하다
  2. 제품을 생성한다.
    • AbstractFactory는 단지 제품을 생성하기 위한 인터페이스를 선언하는 것이고, 그것을 생성하는 책임은 Product의 서브 클래스인 ConcreteProduct에 있다. 
    • 이를 위한 가장 공통적인 방법은 각 제품을 위해 팩토리 메서드를 정의하는 것이다. AbstractFactory는 각 제품 생성을 위한 팩토리 메서드를 재정의(Overrriding) 함으로써 각 제품의 인스턴스를 만든다.
  3. 확장 가능한 팩토리들을 정의한다.
    • AbstractFactory에는 생성할 각 제품의 종류별로 서로 다른 연산(CreateProductA(), CreateProductB())을 정의한다. CreateProductA를 통해 ProductA를 만든다.
    • 새로운 종류의 제품이 추가되면 AbstractFactory의 인터페이스에도 새로운 연산을 추가해야 한다. 좀 더 유연하게 하려면 생성할 객체를 매개변수로 만들어 연산에 넘기면 된다. 

 

참고문헌

  1. <GoF의 디자인패턴> 에릭 감마 외 3인 저