📌 팩토리 메서드 패턴 (Factory Method Pattern) 이란?
팩토리 메서드 패턴은 객체 생성을 캡슐화하고 서브 클래스에서 어떤 클래스의 인스턴스를 만들지 결정하는 디자인 패턴 중 하나이다.
이 패턴을 사용하면 클라이언트 코드가 구체적인 클래스에 의존하지 않고도 객체를 생성할 수 있으며, 새로운 클래스를 추가하거나 기존 클래스를 변경할 때에도 클라이언트 코드를 수정하지 않아도 된다.
클라이언트에서 직접 생성자를 통해 구체적인 객체를 생성하는 것이 아닌, 구체적인 객체들을 도맡아 생성하는 팩토리 클래스를 만들고, 이를 상속하는 구체 팩토리 클래스의 메서드에서 여러 가지 구체적인 객체 생성을 각각 책임지는 것이다.
객체 생성에 필요한 과정을 템플릿화시키고 객체 생성에 관한 전처리 혹은 후처리를 통해 생성 과정을 다양하게 처리할 수 있기에 객체를 유연하게 생성할 수 있다.
📌 팩토리 메서드 구조
[ Product ]
팩토리 메서드가 생성하는 객체의 인터페이스
[ ConcreteProduct ]
Product 인터페이스를 실제로 구현하는 클래스
[ Creator ]
최상위 공장 클래스로서, Product 타입의 객체를 반환하는 팩토리 메서드를 추상화하여 서브 클래스로 하여금 구현하도록 한다.
[ ConcreteCreator ]
서브 공장 클래스로서 이에 맞는 제품 객체를 반환하도록 추상 메서드를 재정의한다.
제품 객체 하나당 그에 걸맞는 생산 공장 객체가 위치된다.
📌 팩토리 메서드 패턴 구현 방법
Creator를 추상 클래스로 정의하고, 팩토리 메서드는 abstract로 선언하는 방법과 Creator가 구체 클래스이고, 팩토리 메서드의 기본 구현을 제공하는 방법이 있다.
또한 자바 8 버전 이후 추가된 인터페이스의 디폴트 메서드를 통해 팩토리 메서드를 선언할 수 있다.
[ 제품군 ]
public interface Product {
void whoAmI();
}
public class ConcreteProductA implements Product{
@Override
public void whoAmI() {
System.out.println("A");
}
}
public class ConcreteProductB implements Product{
@Override
public void whoAmI() {
System.out.println("B");
}
}
[ 공장군 ]
public abstract class ProductFactory {
public abstract Product createProduct();
}
public class ConcreteProductAFactory extends ProductFactory{
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
public class ConcreteProductBFactory extends ProductFactory{
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
[ 클라이언트 ]
public class Client {
public static void main(String[] args) {
ProductFactory productFactory = new ConcreteProductBFactory();
Product productB = productFactory.createProduct();
productFactory = new ConcreteProductAFactory();
Product productA = productFactory.createProduct();
productA.whoAmI(); // 실행 결과 "A"
productB.whoAmI(); // 실행 결과 "B"
}
}
📌 팩토리 메서드 패턴 사용 상황
[ 객체 생성의 유연성이 필요한 경우 ]
팩토리 메서드 패턴을 사용하면 객체 생성을 서브 클래스로 분리함으로써 새로운 클래스를 추가하거나 기존 클래스를 수정할 때 클라이언트 코드를 변경하지 않고도 새로운 객체를 생성할 수 있다.
[ 클래스의 인스턴스화를 지연하려는 경우 ]
객체 생성을 팩토리 메서드에 위임함으로써 필요한 시점에 객체를 생성할 수 있다.
자원이 많이 소모되는 경우나 성능에 민감한 상황에서 유용하다.
[ 컴포넌트의 독립성을 유지하려는 경우 ]
팩토리 메서드 패턴은 객체 생성을 서브 클래스로 분리하므로, 각 서브 클래스는 특정 구현에 대한 책임을 가지게 된다.
이는 각 클래스 간의 독립성을 유지하고 시스템을 더 쉽게 관리할 수 있도록 도와준다.
[ 클래스 계통의 확장이 용이한 경우 ]
팩토리 메서드 패턴을 사용하면 새로운 클래스를 추가하기 간편하다.
새로운 제품이나 서비스가 도입되면 그에 해당하는 팩토리 메서드를 추가하여 기존 시스템에 영향을 최소화할 수 있다.
📌 팩토리 메서드 패턴의 장 / 단점
[ 장점 ]
- 유연성과 확장성
- 새로운 클래스를 추가하거나 기존 클래스를 수정하지 않고도 객체 생성을 확장할 수 있다.
- 코드 재사용
- 생성 로직을 분리함으로써 코드의 재사용성을 높일 수 있다.
- 여러 클래스에서 공통적으로 사용되는 생성 로직은 부모 클래스의 팩토리 메서드에서 정의하고 각 클래스에서 이를 상속하여 사용하면 된다.
- 클라이언트 코드의 단순화
- 클라이언트 코드가 구체적인 클래스에 의존하지 않고도 객체를 생성할 수 있기에 클라이언트 코드가 단순화되고 유지보수를 용이하게 한다.
[ 단점 ]
- 클래스 수의 증가
- 각각의 제품에 대한 구체적인 생성자를 갖는 클래스를 만들어야 하기 때문에 클래스의 수가 많아지고 코드의 복잡성이 증가할 수 있다.
- 추상화의 어려움
- 팩토리 메서드 패턴은 객체 생성을 추상화하는데 도움을 주지만, 추상화를 위해 새로운 인터페이스나 추상 클래스를 도입해야 하는데 이로 인해 초기 구현이 복잡해질 수 있다.
- 클래스 계통의 복잡성
- 각 제품에 대한 팩토리 메서드를 정의하고, 이를 상속하는 서브 클래스들을 추가하면서 계층이 깊어지게 된다.
- 코드의 이해와 유지보수가 어려워질 수 있다.
📌 자바 속 팩토리 메서드 패턴
[ Calendar ]
public abstract class Calendar {
// ...
public static Calendar getInstance() {
// 시스템의 디폴트 로케일 및 타임존을 기반으로 새로운 Calendar 인스턴스를 반환
// 구체적인 구현은 시스템에 따라 달라질 수 있음
return new GregorianCalendar();
}
// ...
}
Calendar.getInstance() 메서드는 시스템의 디폴트 로케일과 타임존을 기반으로 Calendar의 구현체를 반환한다.
[ NumberFormat ]
public abstract class NumberFormat {
// ...
public static NumberFormat getInstance() {
// 시스템의 디폴트 로케일을 기반으로 NumberFormat 인스턴스를 반환
// 구체적인 구현은 시스템에 따라 달라질 수 있음
return getInstance(Locale.getDefault(Locale.Category.FORMAT));
}
public static NumberFormat getInstance(Locale inLocale) {
// inLocale에 따라 적절한 NumberFormat 인스턴스를 반환
// 구체적인 구현은 inLocale에 따라 달라질 수 있음
return getNumberInstance(inLocale);
}
// ...
}
NumberFormat.getInstance() 메서드는 시스템의 디폴트 로케일을 기반으로 NumberFormat의 구현체를 반환한다.
📌 정리
팩토리 메서드 패턴은 객체 생성을 서브 클래스로 분리하여, 어떤 클래스의 인스턴스를 생성할지에 대한 결정을 서브 클래스에게 내리게 하는 디자인 패턴이다. 이 패턴은 객체 생성의 유연성을 제공하고 클라이언트 코드가 구체적인 클래스에 의존하지 않도록 도와준다.
다음과 같을 때 사용하면 좋다
- 객체 생성 시 특정 로직이나 알고리즘이 필요한 경우
- 객체의 생성이 서브 클래스에 의존적일 때
- 객체 생성 시 특정 조건에 따라 다른 클래스의 인스턴스를 생성해야 하는 경우
팩토리 메서드 패턴을 사용하면 아래와 같은 이점을 얻을 수 있다.
- 유연성 및 확장성
- 클라이언트 코드 단순화
- 재사용성
'OOP > Design Pattern' 카테고리의 다른 글
[Design Pattern] 프로토타입 패턴(Prototype Pattern)이란? (0) | 2024.03.07 |
---|---|
[Design Pattern] 추상 팩토리 패턴(Abstract Factory Pattern)이란? (0) | 2024.03.06 |
[Design Pattern] 빌더 패턴(Builder Pattern)이란? (0) | 2024.03.04 |
[Design Pattern] 싱글턴 패턴(Singleton Pattern)이란? (2) | 2024.02.28 |
[Design Pattern] 생성 패턴이란? (0) | 2024.02.26 |