mojo's Blog
Factory Method Pattern & Abstract Factory Pattern 본문
※ Creational patterns
- 새 연산자를 명시적으로 사용하지 않고 새 객체를 만들 수 있음
- 클라이언트 코드를 수정하지 않고도 다양한 객체를 객체화할 수 있음
- ex) Factory Method, Abstract Factory, Singleton, Builder, Prototype
Factory Method
- 상속을 사용하여 객체화할 객체를 결정함
Abstract Factory
- 객체 생성을 팩토리 객체에 위임함
Factory Method Pattern
Hamburger orderHamburger(String type) {
Hamburger hamburger;
if (type.equals("cheese"))
hamburger = new CheeseHamburger();
else if (type.equals("greek"))
hamburger = new GreekHamburger();
else if (type.equals("pepperoni"))
hamburger = new PepperoniHamburger();
hamburger.prepare();
...
hamburger.box();
return hamburger;
}
타입에 따른 햄버거 객체를 생성하여 리턴하는 코드이다.
햄버거를 타입에 따라 객체를 생성하는 단순한 팩토리를 생성하면 다음과 같다.
public class SimpleHamburgerFactory {
public Hamburger createHamburger(String type) {
Hamburger hamburger;
if (type.equals("cheese"))
hamburger = new CheeseHamburger();
else if (type.equals("greek"))
hamburger = new GreekHamburger();
else if (type.equals("pepperoni"))
hamburger = new PepperoniHamburger();
return hamburger;
}
}
위와 같이 팩토리를 활용하여 햄버거 객체를 생성해내는 메서드가 있다.
이를 활용하여 햄버거를 주문하는 코드를 수정하면 다음과 같다.
public class HamburgerStore {
SimpleHamburgerFactory factory;
public HamburgerStore(SimpleHamburgerFactory factory) {
this.factory = factory
}
public Hamburger orderHamburger(String type) {
Hamburger hamburger;
hamburger = factory.createHamburger(type);
hamburger.prepare();
...
hamburger.box();
return hamburger;
}
}
위와 같은 팩토리 구조를 다이어그램으로 나타내면 다음과 같다.
※ Franchising the hamburger store
다른 스타일로 NY, Chicago, California 등이 있다고 한다면,
다른 햄버거 팩토리로는 아래와 같이 만들 수 있다.
- NYHamburgerFactory
- ChicagoHamburgerFactory
- CaliforniaHamburgerFactory
NYHamburgerFactory nyFactory = new NYHamburgerFactory();
HamburgerStore nyStore = new HamburgerStore(nyFactory);
nyStore.order("Cheese");
ChicagoHamburgerFactory chicagoFactory = new ChicagoHamburgerFactory();
HamburgerStore chicagoStore = new HamburgerStore(chicagoFactory);
chicagoStore.order("greek");
목적: 객체를 만드는 방법을 노출하여 하위 클래스가 실제 생성 프로세스를 제어할 수 있도록 함
사용시기
- 클래스는 어떤 클래스를 만들어야 하는지 알 수 없음
- 하위 클래스는 생성할 객체를 지정할 수 있음
- 부모 클래스는 생성을 하위 클래스로 미뤄야 함
※ Requirement Change
이제 가게와 햄버거 생성을 연결하는 틀을 만들 필요가 있다.
public abstract class HamburgerStore {
public Hamburger orderHamburger(String type) {
Hamburger hamburger;
hamburger = createHamburger(type);
hamburger.prepare();
...
hamburger.box();
return hamburger;
}
protected abstract Hamburger createHamburger(String type);
}
예를 들어 햄버거를 준비하는 서비스를 제공하는 OO framework 이다.
프레임워크는 createHamburger() 팩토리 메서드를 호출하여 잘 정의하고 일관된 프로세스를 사용하여 준비할 수 있는 햄버거를 만든다.
프레임워크의 "클라이언트"는 이 클래스를 하위 클래스로 분류하고 createHamburger() 메서드의 구현을 제공한다.
구체적인 "product" 클래스에 대한 종속성은 하위 클래스에 캡슐화된다.
// NYHamburgerStore -> HamburgerStore
public Hamburger createHamburger(String type) {
Hamburger hamburger;
if (type.equals("cheese")) {
hamburger = new NYStyleCheeseHamburger();
} else if (type.equals("greek")) {
hamburger = new NYStyleGreekHamburger();
}
return hamburger;
}
// ChicagoHamburgerStore -> HamburgerStore
public Hamburger createHamburger(String type) {
Hamburger hamburger;
if (type.equals("cheese")) {
hamburger = new ChicagoStyleCheeseHamburger();
} else if (type.equals("greek")) {
hamburger = new ChicagoStyleGreekHamburger();
}
return hamburger;
}
팩토리 메서드를 사용하여 햄버거를 주문하는 순서는 아래와 같다.
1. HamburgerStore 객체를 생성한다.
HamburgerStore nyHamburgerStore = new NYHamburgerStore();
2. orderHamburger 메서드를 호출한다.
nyHamburgerStore.orderHamburger("cheese");
3. orderHamburger 메서드는 createHamburger 메서드를 호출한다.
Hamburger hamburger = createHamburger("cheese");
4. 햄버거를 생성하면, prepare 및 box 등 주문 준비를 한다.
hamburger.prepare() -> ... -> hambureger.box()
- Creator Class: NYHamburgerStore, ChicagoHamburgerStore
- Product Class: Hamburger
※ Design Principle: Dependency Inversion Principle
- 추상화에 의존하며, 구체적인 클래스에 의존하지 않음
- 높은 수준의 컴포넌트는 낮은 수준의 컴포넌트에 의존해서는 안 됨
- 팩토리 메서드는 의존성 반전 원리를 따르는 한 가지 방법
※ Factory Method Pattern
하위 클래스에서 객체화할 클래스를 결정할 수 있다.
- Create 클래스는 실제 Concrete Product 클래스를 객체화할 수 없는 방식으로 작성됨
- 객체화할 Concrete Product 클래스는 응용 프로그램에서 객체화하여 사용하는 Concrete Product 클래스에
따라 결정됨
- 하위 클래스가 생성할 Concrete Product 클래스를 런타임에 결정한다는 의미는 아님
Abstract Factory Pattern
목적: 특정 객체를 전달하기 위해 생성 호출을 하나 이상의 구체 클래스에 위임하는 인터페이스 제공
사용시기
- 객체의 생성은 객체를 활용하는 시스템과 독립적이여야 함
- 시스템은 여러 객체 제품군을 사용할 수 있어야 함
- 객체 패밀리는 함께 사용해야 함
- 라이브러리는 구현 세부 정보를 노출하지 않고 게시해야 함
- 구체 클래스는 클라이언트와 분리되어야 함
추상 팩토리 패턴은 팩토리 메서드 패턴보다 한 단계 높은 추상화이다.
- 추상 팩토리 패턴: 컴포지션 사용
- 팩토리 메서드 패턴: 상속 사용
※ Participants
- AbstractFactory: 추상적 제품 객체를 만드는 작업에 대한 인터페이스 선언
- ConcreteFactory: 구체적인 제품 객체를 만들기 위한 작업 구현
- AbstractProduct: 제품 객체 유형에 대한 인터페이스 선언
- ConcreteProduct: 해당 구체 팩토리에서 생성할 제품 객체 정의
- Client: AbstractFactory 및 AbstractProduct 클래스에서 선언한 인터페이스만 사용
※ When to Use Abstract Factory Pattern?
1. 생성 패턴에 공통적인 것
- 시스템은 제품이 생성, 구성 및 표현되는 방식과 독립적이여야 함
- 클래스가 생성해야 하는 객체의 클래스를 예측할 수 없음
2. 추상 팩토리 패턴을 특정화
- 시스템은 제품군 중 하나를 사용해야 함
- 관련 제품 객체 제품군은 함께 사용할 수 있도록 설계되며 제약 조건을 적용해야 함
※ Consequences
장점
- 구체 클래스를 분리
- 제품군 교환이 용이함
- 제품 간의 일관성을 촉진함
단점
- 새로운 종류의 제품 지원이 어려움
'Design Patterns' 카테고리의 다른 글
Singleton Pattern (1) | 2024.06.09 |
---|---|
Builder Pattern (0) | 2024.06.09 |
Mediator Pattern (0) | 2024.06.06 |
State Pattern (0) | 2024.06.06 |
Template Method Pattern (0) | 2024.06.06 |