💡 팩토리 메서드란
객체 생성을 공장 클래스로 캡슐화 처리하여 대신 생성하게 하는 생성 디자인 패턴입니다.
자식 클래스들이 팩토리 메서드를 오버라이딩 해 생성될 객체들의 유형을 변경할 수 있도록 하는 패턴입니다.
즉, Client에서 직접 new 연산자로 객체를 생성하지 않고, 제품 객체들을 도맡아 생성하는 공장 클래스를 만들고,
이를 상속하는 공장 클래스 메서드에서 여러가지 제품 객체 생성을 각각 책임지는 것입니다.
팩토리 메소드 패턴은 객체를 만들어내는 공장(Factory 객체)을 만드는 패턴입니다.
어떤 클래스의 인스턴스를 만들지는 미리 정의한 공장 서브 클래스에서 결정합니다.
💡 팩토리 메서드 기본 구조
공장 객체와 제품 객체 간 느슨한 결합 구조로 이루어 집니다.
이와 같은 구조는 객체 간의 결합도를 낮춰주어 유지 보수가 용이합니다.
팩토리 메서드 패턴은 상위 클래스에서 객체를 생성하는 인터페이스를 정의하고,
하위 클래스에서 인스턴스를 생성하도록 하는 방식으로, 상위 클래스에서는 인스턴스를 만드는
방법만 결정하고, 하위 클래스에서 그 데이터의 생성을 책임지고 조작하는 함수들을 오버라이딩하여
인터페이스와 실제 객체를 생성하는 클래스를 분리할 수 있는 특성을 갖는 디자인 패턴입니다.
팩토리 메서드 패턴은 생성할 객체의 클래스를 국한하지 않고 객체를 생성합니다.
1. Creator
Creator 이름에 불구하고 주 책임은 제품을 생성하는 것이 아닙니다.
일반적으로 크리에이터 클래스에 이미 제품 관련 핵심 비즈니스 로직이 있으며,
팩토리 메서드는 이 로직을 ConcreteCreator 클래스로부터 디커플링(분리) 하는데 도움을 줄 뿐입니다.
최상위 공장 클래스로, 팩토리 메서드를 추상화(abstract)하여 서브 클래스로 하여금 구현하도록 합니다.
- 객체 생성 처리 메서드 (someOperation) : 객체 생성 관한 전/후처리를 템플릿화한 메소드
- 팩토리 메서드 (createProduct) : 서브 공장 클래스에서 재정의할 객체 생성 추상 메서드
2. Concrete Creator
각 서브 공장 클래스들은 이에 맞는 제품 객체를 반환하도록 생성 추상 메소드를 재정의 합니다.
즉, 제품 객체 하나당 그에 걸맞는 생산 공장 객체가 위치됩니다.
3. Product
제품 구현체를 추상화 합니다.
4. Concrete Product
제품 구현체
💡 팩토리 메서드 구현 예제
아래 예제는 다양한 OS에 맞는 UI 컴포넌트를 적용한 UI 프레임워크 입니다.
Window에는 Window 스타일 버튼을, MacOS에는 macOS 스타일 버튼을 렌더링 해주어야 합니다.
1. Creator
// 추상 팩토리 클래스
abstract class UIFactory {
public abstract Button createButton();
}
2. Concrete Creator
// 구체적인 팩토리 클래스
class WindowsFactory extends UIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
}
class MacOSFactory extends UIFactory {
@Override
public Button createButton() {
return new MacOSButton();
}
}
3. Product
// 추상 제품(UI 컴포넌트) 인터페이스
interface Button {
void render();
}
4. Concrete Product
// 구체적인 제품 클래스
class WindowsButton implements Button {
@Override
public void render() {
System.out.println("Rendering Windows button");
}
}
class MacOSButton implements Button {
@Override
public void render() {
System.out.println("Rendering MacOS button");
}
}
5. Client
// 클라이언트 코드
public class FactoryMethodPatternDemo {
private static UIFactory factory;
public static void main(String[] args) {
// 운영체제에 따라 적절한 팩토리 설정
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("win")) {
factory = new WindowsFactory();
} else if (osName.contains("mac")) {
factory = new MacOSFactory();
}
// 팩토리를 통해 UI 컴포넌트 생성
Button button = factory.createButton();
button.render();
}
}
💡 결론
팩토리 메서드는 생성자(Creator)와 구현 객체(Concrete Product)의 강한 결합을 피할 수 있습니다.
캡슐화, 추상화를 통해 생성되는 객체의 구체적인 타입을 감출 수 있습니다.
이는 단일 책임 원칙과 개방/폐쇄 원칙을 준수하며, 생성에 대한 인터페이스 부분과 생성에 대한 구현 부분을 나누어
패키지를 분리하여 아래와 같이 개별로 여러 개발자가 협업을 통해 개발합니다.
제품 구현체마다 팩토리 객체들을 모두 구현해 주어야 해서, 구현체가 늘어날 때마다
팩토리 클래스가 증가하여 서브 클래스 수가 폭발하고 코드 복잡성이 증가하는 문제가 있습니다.