팩토리 메서드 패턴과 추상 팩토리 패턴은 객체 생성을 캡슐화 하는 패턴이며,
클라이언트와 구상 클래스가 서로 분리된 유연한 디자인을 구현할 수 있게 도와준다.
- 팩토리 메서드: “어떤 구체 Product를 만들지”를 하위 Creator가 결정한다
- 추상 팩토리: “어떤 제품군(여러 Product 계층) 을 만들지”를 팩토리 인스턴스 교체로 결정한다
언제 어떤 패턴을 쓰나?
- 팩토리 메서드
- 한 제품 계층만 다루고, 구체 타입 선택을 상속(하위 Creator) 으로 바꾸고 싶을 때.
- 상위 로직(템플릿) 속에서 객체 생성 지점을 오버라이드로 바꾸고 싶을 때.
- 클래스 수가 비교적 적고 “템플릿 메서드” 흐름이 중요할 때.
- 추상 팩토리
- 여러 제품 계층(예: Button/Checkbox/…)이 세트(제품군) 로 맞물려야 할 때.
- 런타임에 환경별 세트 교체(Win ↔ Mac, Dev ↔ Prod)를 깔끔히 하고 싶을 때.
- DI 컨테이너와 궁합이 좋음(팩토리 빈을 주입해 세트 스위칭).
장단점 요약
- 팩토리 메서드
- 장점: 상위 로직 재사용 + 하위에서 객체 선택 유연. 템플릿/훅 구조와 친함.
- 단점: 제품군이 늘어나면 Creator/ConcreteCreator 조합이 많아질 수 있음.
- 추상 팩토리
- 장점: 제품군의 일관성 보장(혼종 방지), 세트 교체 용이.
- 단점: 제품 계층·팩토리 인터페이스가 늘면서 구조가 커짐.
1) 팩토리 메서드 패턴 (Java 예제)
한 가지 Product 계층을 만들되, 어떤 구현체를 만들지는 하위 Creator가 결정.
// Product 계층
interface Transport {
void deliver();
}
class Truck implements Transport {
public void deliver() { System.out.println("Deliver by road in a box"); }
}
class Ship implements Transport {
public void deliver() { System.out.println("Deliver by sea in a container"); }
}
// Creator 계층
abstract class Logistics {
// 팩토리 메서드: 어떤 구체 Product를 만들지는 하위 클래스가 결정
protected abstract Transport createTransport();
// 비즈니스 로직(템플릿): 공통 흐름 안에서 Product 사용
public void planDelivery() {
Transport t = createTransport();
System.out.println("Planning route...");
t.deliver();
}
}
class RoadLogistics extends Logistics {
@Override protected Transport createTransport() { return new Truck(); }
}
class SeaLogistics extends Logistics {
@Override protected Transport createTransport() { return new Ship(); }
}
// 사용
public class FactoryMethodDemo {
public static void main(String[] args) {
Logistics road = new RoadLogistics();
road.planDelivery(); // -> Truck 생성
Logistics sea = new SeaLogistics();
sea.planDelivery(); // -> Ship 생성
}
}
핵심 포인트
- createTransport()가 “팩토리 메서드”.
- 상위 Logistics는 공통 알고리즘(planDelivery)을 제공하고, 구체 객체 선택은 하위 클래스가 결정.
2) 추상 팩토리 패턴 (Java 예제)
버튼/체크박스처럼 여러 제품 계층이 있는 “제품군”을 OS별로 일관되게 생성.
// 제품 계층 1
interface Button {
void render();
}
// 제품 계층 2
interface Checkbox {
void check();
}
// 제품군 A (Windows)
class WinButton implements Button {
public void render() { System.out.println("Render Windows Button"); }
}
class WinCheckbox implements Checkbox {
public void check() { System.out.println("Check Windows Checkbox"); }
}
// 제품군 B (Mac)
class MacButton implements Button {
public void render() { System.out.println("Render Mac Button"); }
}
class MacCheckbox implements Checkbox {
public void check() { System.out.println("Check Mac Checkbox"); }
}
// 추상 팩토리: 제품군을 통째로 생성
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// 구체 팩토리: 특정 제품군을 생성
class WinFactory implements GUIFactory {
public Button createButton() { return new WinButton(); }
public Checkbox createCheckbox() { return new WinCheckbox(); }
}
class MacFactory implements GUIFactory {
public Button createButton() { return new MacButton(); }
public Checkbox createCheckbox() { return new MacCheckbox(); }
}
// 클라이언트: 팩토리를 주입받아 일관된 제품군 사용
class Application {
private final Button button;
private final Checkbox checkbox;
public Application(GUIFactory factory) {
this.button = factory.createButton();
this.checkbox = factory.createCheckbox();
}
public void drawUI() {
button.render();
checkbox.check();
}
}
public class AbstractFactoryDemo {
public static void main(String[] args) {
GUIFactory factory = detectOSIsWindows() ? new WinFactory() : new MacFactory();
Application app = new Application(factory);
app.drawUI();
}
private static boolean detectOSIsWindows() {
String os = System.getProperty("os.name", "").toLowerCase();
return os.contains("win");
}
}
핵심 포인트
- GUIFactory가 “추상 팩토리”.
- 클라이언트는 팩토리만 바꾸면 여러 제품 계층(Button, Checkbox) 을 일관된 제품군으로 교체.
'Java > DesignPattern' 카테고리의 다른 글
| Singleton Pattern 싱글턴 패턴 (0) | 2025.09.07 |
|---|---|
| 템플릿 메소드 패턴 (0) | 2024.06.03 |
| 팩토리 메서드 패턴 (0) | 2024.05.16 |
| MVVM 패턴 (0) | 2023.07.27 |