본문 바로가기
SW

GoF의 디자인 패턴(Design Patterns: Elements of Reusable Object-Oriented Software) - 3장 생성 패턴 :: 추상 팩토리(Abstract Factory)

by 라꾸스떼(YR) 2020. 4. 17.
반응형

[추상 팩토리(Abstract Factory) - 객체 생성(Object Creational)]

<의도>

상세화된 서브클래스를 정의하지 않고도 서로 관련성이 있거나 독립적인 여러 객체의 군을 생성하기 위한 인터페이스를 제공한다.

 

<동기>

서로 다른 룩앤필은 서로 다른 사용자 인터페이스의 표현 방식과 행동을 갖는다. 개발한 응용프로그램이 서로 다른 룩앤필 표준에 상관없이 이식성을 가지려면, 응용프로그램이 각 사용자 인터페이스 툴킷에서 제공하는 위젯을 직접 사용하지 못하도록 해야 한다. 이런 문제는 구체적 사용자 인터페이스의 위젯을 사용하지 말고 추상 클래스인 WidgetFactory를 정의하여 해결하는 게 좋다. WidgetFactory 클래스는 위젯의 기본 사용자 인터페이스 요소(윈도우, 스크롤바, 버튼 등)를 생성할 수 있는 인터페이스를 정의한다. 그리고 응용프로그램은 필요한 사용자 인터페이스 요소를 WidgetFactory에 생성해 줄 것을 요청하여, 필요한 요소의 인스턴스를 얻어온다. 물론, 실제적으로 구현 종속적인 인스턴스를 생성하기 위해서는 팩토리와 구분하여 각각의 위젯별로 추상화된 클래스를 정의해야 하고, 이를 상속하는 구체적인 서브클래스를 정의하여 구체적 룩앤필 표준에 대한 구현을 제공한다.

사용자는 WidgetFactory를 상속받은 어떤 구체적 서브클래스가 이들 연산을 구현하여 결과를 반환하는지 알 수 없고, 알 필요도 없다. 즉, 사용자는 팩토리에만 메시지를 보낼 뿐이다.

 

<활용성>

-객체가 생성되거나 구성 : 표현되는 방식과 무관하게 시스템을 독립적으로 만들고자 할 때

-여러 제품군 중 하나를 선택해서 시스템을 설정해야 하고 한번 구성한 제품을 다른 것으로 데체할 수 있을 때

-관련된 제품 객체들이 함께 사용되도록 설계되었고, 이 부분에 대한 제약이 외부에도 지켜지도록 하고 싶을 때

-제품에 대한 클래스 라이브러리를 제공하고, 그들의 구현이 아닌 인터페이스를 노출시키고 싶을 때

 

<구조>

-

 

<참여자>

-AbstractFactory : 개념적 제품에 대한 객체를 생성하는 연산으로 인터페이스를 정의한다.

-ConcreteFactory : 구체적인 제품에 대한 객체를 생성하는 연산을 구현한다.

-AbstractProduct : 개념적 제품 객체에 대한 인터페이스를 정의한다.

-ConcreteProduct : 구체적으로 팩토리가 생성할 객체를 정의하고, AbstractProduct가 정의하는 인터페이스를 구현한다.

-Client : AbstractFactory와 AbstractProduct 클래스에 선언된 인터페이스를 사용한다.

 

<협력 방법>

-구체 팩토리(Concrete Factory)는 어떤 특정 구현을 갖는 제품 객체를 생성한다. 서로 다른 제품 객체를 생성하려면 사용자는 서로 다른 구체 팩토리를 사용해야 한다.

-AbstractFactory는 필요한 제품 객체를 생성하는 책임을 ConcreteFactory 서브 클래스에 위임한다.

 

<결과>

1.구체적인 클래스를 분리한다 : 추상 팩토리 패턴을 쓰면 응용프로그램이 생성할 객체의 클래스를 제어할 수 있다. 팩토리는 제품 객체를 생성하는 과정과 책임을 캡슐화한 것이기 때문에, 구체적인 구현 클래스가 사용자에게서 분리된다.

2.제품군을 쉽게 대체할 수 있도록 한다 : 구체 팩토리의 클래스는 응용프로그램에서 한 번만 나타나기 때문에 응용프로그램이 사용할 구체 팩토리를 변경하기는 쉽다. 추상 팩토리는 필요한 모든 것을 생성하기 때문에 전체 제품군은 한번에 변경이 가능하다.

3.제품 사이의 일관성을 증진시킨다 : 하나의 군 안에 속한 제품 객체들이 함께 동작하도록 설계되어 있을 때, 응용프로그램은 한 번에 오직 한 군에서 만든 객체를 사용하도록 함으로써 프로그램의 일관성을 갖도록 해야 한다.

4.새로운 종류의 제품을 제공하기 어렵다 : 새로운 종류의 제품을 만들기 위해 기존 추상 팩토리를 확장하기가 쉽지 않다. 만약 새로운 종류의 제품이 등장하면 팩토리의 구현을 변경해야 한다. 이는 추상 팩토리와 모든 서브클래스의 변경을 가져온다. 즉, 인터페이스가 변경되는 새로운 제품을 생성하는 연산이 추가되거나, 기존 연산의 반환 객체 타입이 변경되었으므로, 이를 상속받는 서브클래스 모두 변경되어야 한다.

 

<구현>

1.팩토리를 단일체로 정의한다 : 전형적으로 응용프로그램은 한 제품군에 대해서 하나의 ConcreteFactory 인스턴스만 있으면 된다. 즉, 갖가지 제품의 종류를 만들어 내는 팩토리는 제품군에 대해서 하나면 되는 것이다.

2.제품을 생성한다 : AbstractFactory는 단지 제품을 생성하기 위한 인터페이스를 선언하는 것이고, 그것을 생성하는 책임은 Product의 서브클래스인 ConcreteProduct에 있다. 이를 위한 가장 공통적인 방법은 각 제품을 위해서 팩토리 메서드를 정의하는 것이다. AbstractFactory는 각 제품 생성을 위한 팩토리 메서드를 재정의(overriding)함으로써 각 제품의 인스턴스를 만든다. 제품군이 약간 다르다면 각 제품군을 위한 새로운 구체 팩토리 서브클래스가 필요하다. 구체 팩토리는 원형 패턴을 이용해서 구현할 수 있다. 구체 팩토리가 한 군내의 각 제품 원형 인스턴스로 초기화되고 원형의 복사를 통해서 인스턴스를 생성한다. 원형 기반의 접근법은 새로운 제품군별로 새로운 구체 팩토리를 생성할 필요를 없애준다.

3.확장 가능한 팩토리들을 정의한다 : AbstractFactory에는 생성할 각 제품의 종류별로 서로 다른 연산을 정의한다.

새로운 종류의 제품이 추가되면 AbstractFactory의 인터페이스에도 새로운 연산을 추가해야 한다. 좀더 유연하게 하려면 생성할 객체를 매개변수로 만들어 연산에 넘기면 된다. 이렇게 되면 AbstractFactory에는 Make() 연산만 있으면 되고, Make() 연산의 매개변수로 생성할 제품에 대한 식별자를 넘겨주게 된다.

 

<예제 코드>

-

 

<잘 알려진 사용예>

WidgetKit, DialogKit 등은 사용자 인터페이스 객체를 생성하는 추상 팩토리 클래스이다.

 

<관련 패턴>

AbstractFactory 클래스는 팩토리 메서드 패턴을 이용해서 구현되는데, 원형 패턴을 이용할 때도 있다. 구체 팩토리는 단일체 패턴을 이용해 구현하는 경우가 많다.

반응형

댓글