개발 기록
> [GOF Design Pattern] 생성 패턴 : 팩토리 메서드(Factory Method) 패턴 - 개념과 구현 본문

* 생성 패턴 : 객체 인스턴스를 생성하는 패턴으로, 클라이언트와 생성하고자 하는 객체 인스턴스 사이의 연결을 끊어 주는 패턴이다.
■
1. 팩토리 메서드 패턴 개념
(1) 개념
Factory 클래스를 사용하여 객체를 생성한다. Factory 클래스내의 추상메소드는 new연산자를 통해 객체를 생성하고 반환한다. 즉 Clinet 는 직접 객체를 생성하지 않고, 객체 생성을 담당하는 공장(Factory) 클래스를 이용하여 객체를 생성한다.
어떤 객체를 생성할지는 Factory 클래스를 상속받는 자식 클래스들이 결정하기 때문에 특정 유형에 국한 되지않고 다양한 유형의 객체를 생성할 수 있다.
* 예를 들어 제품 기능 관리 프로그램을 개발 한다고 했을 때, 첫 번째 버전에서는 A기능을 하는 제품이 AA 가 유일했지만 두 번째 버전에서는 BB 제품도 해당 A기능이 가능하다고 해보자.
이럴 경우 기존 코드가 AA 제품에 기준으로 설계되어 있기 때문에 BB 제품을 추가 할려면 AA의 전체 코드를 변경해야 되는 일이 생긴다. 이 때 팩토리 메서드 패턴을 이용하면 특정 조건에 맞는 객체를 생성하는 것에 유연하게 대처할 수 있다.
또한 객체 생성에 필요한 과정을 템플릿 처럼 미리 구성해놓고, 객체 생성에 관한 전처리나 후처리를 통해 생성 과정을 다양하게 처리하여 객체를 유연하게 정할 수 있는 특징도 있다.
☞ 장점
① 결합도를 낮출 수 있다.
② 단일 책임 원칙: 객체 생성 코드를 한 곳 (패키지, 클래스 등)으로 이동하여 코드를 더 쉽게 유지관리할 수 있다
③ 개방/폐쇄 원칙: 기존 클라이언트 코드를 훼손하지 않고 새로운 유형의 객체를 추가할 수 있다.
④ 캡슐화, 추상화를 통해 생성되는 객체의 구체적인 타입을 감출 수 있다.
☞ 단점
① 생성하고자 하는 객체 인스턴스마다 새로운 자식 클래스(Creator 상속 Class)들을 추가해야 하므로 코드의 복잡성이 증가한다. 가장 좋은 방법은 Creator 클래스들의 기존 계층구조에 패턴을 도입하는 것이다.
(2) 구조

▶Product : Creator 클래스와 Creator 의 자식 클래스(ConcreteCreator)들이 생성하는 객체
▶ConcreteProduct : Product interface 의 구현체
▶Creator : 최상위 Factory Class. 새로운 Product 객체를 반환하는 팩토리 메서드를 포함한다. creator 의 주 역할은 Product 객체를 생성하는 것 뿐만이 아니라, Product 객체와 관련된 핵심 비즈니스 로직을 Product class 로부터 분리(디커플링)하는 일도 한다.
- someOperartion() : 객체 생성에 관한 전처리, 후처리를 템플릿화한 메소드
- createProduc() : factory method. ConcreteCreator 클래스에서 재정의 할 객체 생성 추상 메서드
: 팩토리 메서드라고 해서 무조건 새로운 인스턴스들을 생성해야 할 필요는 없다. 기존 객체들을 캐시, 객체 풀 또는 다른 소스로부터 반환할 수도 있다.
: 팩토리 메서드를 abstract(추상)로 선언하여 모든 자식 클래스들이 구현하도록 강제할 수 있으며, 반대로 기본 팩토리 메서드가 default Product Type을 반환하도록 할 수 있다.
▶ConcreteCreator : 최상위 Factory Class 의 자식 Class. 팩토리 메서드를 재정의하여 다른 유형의 Product 을 반환한다.
■
2. 예제
(1) Product Interface 와 구현체 생성
public interface Product {
// 공통으로 처리할 메서드를 선언한다.
void do();
}
public class ConcreteProductA implements Product {
@Override
public void do() {
}
}
public class ConcreteProductB implements Product {
@Override
public void do() {
}
}
(2)[Factory] Creator class 생성
※ Java 8 버전 이후 추가된 인터페이스의 default 키워드로 팩토리 메서드를 선언할 수 있다.
abstract class Creator {
// 객체 생성 전처리 후처리 메소드 (final로 오버라이딩 방지, 템플릿화)
final Product createOperation() {
// 객체 생성 전처리
// 서브 클래스에서 구체화한 팩토리 메서드 실행
Product product = createProduct();
// 객체 생성 후처리 메서드 로직 실행
product.after();
// 전처리 까지 포함한 Product instance 반환
return product;
}
// Factory method 선언: 이 메서드의 반환 유형은 Product interface 타입과 같아야 한다.
// 구체적인 객체 생성 종류는 각 서브 클래스에 위임한다.
abstract protected Product createProduct();
}
(3) ConCreteCreator class 생성
※ product 유형이 너무 많아 모든 Product type 에 대하여 자식 클래스(concreteCreator)들을 만드는 것이 합리적이지 않을 경우, 자식 클래스들의 팩토리 메서드에 인자( argument)를 전달하는 방법도 있다.
// ProductA를 생성하여 반환
class ConcreteCreatorA extends Creator {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// ProductB를 생성하여 반환
class ConcreteCreatorB extends Creator {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
(4) Client class
@RestController
public class TestController {
public void test(){
// 1. 제품A 생성
Creator creator = new ConcreteCreatorA();
Product productA = creator.createOperation();
productA.do();
// 2. 제품B 생성
Creator creator = new ConcreteCreatorB();
Product productB = creator.createOperation();
productB.do();
}
}
■
3. Factory Method 패턴 적용 예시
(1) Spring
Spring은 DI(종속성 주입) 를 할 때 팩토리 메서드 패턴을 사용한다.
1. Creator : BeanFactory
각각의 getBean 메소드는 빈을 리턴하는 팩토리 메소드이다 . ApplicationContext 인터페이스는 BeanFactory 를 확장한다. Spring은 이 구성을 사용하여 XML 파일이나 Java 주석과 같은 일부 외부 구성을 기반으로 빈 컨테이너를 시작한다.
public interface BeanFactory {
getBean(Class<T> requiredType);
getBean(Class<T> requiredType, Object... args);
getBean(String name);
// ...
]
2. ConcreteCreator
ApplicationContext 인터페이스의 구현 클래스를 사용하여(ex.AnnotationConfigApplicationContext) BeanFactory 인터페이스의 팩토리 메소드를 상속받아 빈을 생성할 수 있다
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
Foo foo = context.getBean(Foo.class);
Bar bar = context.getBean(Bar.class);
■
4. Factory Method 변형 패턴
: Factory class 의 서브 클래스가 늘어나는 팩토리 메서드 패턴의 단점을 개선 시킨 패턴
(1) Enum Factory Method Pattern
팩토리 클래스를 자바 Enum으로 구성한 패턴이다. Enums 객체는 상속이 안된다는 한계가 있다.
(2) Dinamic Factory Pattern (Reflection API 사용)
팩토리 메서드 패턴의 큰 단점은 제품 객체의 갯수마다 공장 서브 클래스를 모두 구현해야되서 클래스 폭발이 일어날수 있다는 점인데, 이를 Reflection API를 이용해 동적으로 처리하여 서브 클래스 폭발을 막는 패턴이다.
■
5 다른 패턴과의 관계
☞ 자식 클래스를 이용하여 커스터마이징 한다는 점에서 팩토리메서드-> 추상팩토리-> 프로토타입 or 빌더 패턴으로 확장할 수 있다.
(1) Factory Method vs Prototype
프로토 타입은 상속을 기반으로 하지 않으므로 상속과 관련된 이슈는 없지만 복제된 객체의 초기화를 위한 복잡한 과정이 필요하다. 팩토리 메서드는 상속을 기반으로 하지만 초기화 단계가 필요하지 않다.
(2) Factory Method vs Template Method
| 팩토리 메소드 패턴 | 템플릿 메서드 패턴 | |
| 패턴 종류 | 생성 패턴 | 행동 패턴 |
| 공통점 | 상위 클래스에서는 추상적으로 표현하고 그 구체적인 유형은 하위 클래스에서 결정 | |
| 차이점 | 하위 클래스는 객체 생성 구현 | 하위클래스는 전략 알고리즘 구현 |
(3) Factory Method vs Abstract Factory
- 추상 팩토리 패턴은 팩토리 메서드 패턴보다 한 단계 높은 추상화 수준이다.
- 추상 팩토리 클래스들은 팩토리 메서드들의 집합을 기반으로 하는 경우가 많다.
| 팩토리 메서드 패턴 | 추상 팩토리 패턴 | |
| 패턴 종류 | 생성 패턴 | 생성 패턴 |
| 공통점 | 객체의 생성을 Factory 클래스가 담당하며 구체적인 타입을 Factory 하위 클래스가 결정한다. | |
| 차이점 | 한 Factory당 한 종류의 객체 생성 지원 CreatorA -> ProductA CreatorB -> ProductB |
한 Factory에서 서로 연관되거나 의존적인 객체로 이루어진 Product 객체 생성 CreatorA -> ProductA, ProductB |
참고
https://refactoring.guru/ko/design-patterns/factory-comparison
'디자인 패턴' 카테고리의 다른 글
| > [GOF Design Pattern] 행동 패턴 : 옵저버 (Observer) 패턴 - 개념과 구현 (0) | 2024.05.17 |
|---|---|
| > [GOF Design Pattern] 행동 패턴 : 커맨드 (Command) 패턴 - 개념과 구현 (0) | 2024.03.06 |
| > [GOF Design Pattern] 행동 패턴 : 전략 (Strategy) 패턴 - 개념과 구현 (6) | 2024.02.05 |
| > [GOF Design Pattern] 구조 패턴 : 프록시(Proxy) 패턴 - 개념과 구현 (0) | 2024.01.17 |
| > 디자인 패턴에 대해 알아보기 - 개념과 유형 (0) | 2024.01.17 |