2022. 1. 3. 00:18ㆍETC/Design Patterns
Factory Method Pattern
Define an interface for creating an object, but let subclasses decide which class to instantiate.
Factory Method lets a class defer instantiation to subclasses.
- GoF Design Patterns
팩토리 메서드 패턴은 상위 클래스에서 객체의 인터페이스를 정의하고, 하위 클래스가 객체를 생성할지를 결정하도록 하는 패턴입니다. 객체를 하위 클래스에서 생성되도록 시키는 것이죠.
Factory Method Pattern는 Factory와 Template Method Pattern이 결합된 형태입니다.
vs Simple Factory
Factory Method Pattern은 Simple Factory에 추상화를 더한 개념입니다.
Simple Factory는 분리된 클래스에 생성 코드를 직접 구현했다면,
Factory Method는 추상화된 상위 클래스 인터페이스를 하위 클래스에서 직접 객체를 생성합니다.
vs Template Method
Factory Method 패턴은 Template Method 패턴과 유사한 모습을 가지고 있습니다.
Factory Method도 실제 생성되는 알고리즘을 하위 메서드로 위임하는데, 실제 구현을 위임한다는 측면에서 Template Method 패턴과 유사하다고 볼 수 있습니다.
Template Method 과의 관계를 정리하자면,
공통점 : 추상화를 사용해 객체를 생성하며, 상위 클래스에서 정의를 결정하고 하위 클래스에 구체적인 처리를 위임합니다.
차이점 : 해결하려는 목적에 따라 두 패턴에 차이가 있습니다.
Factory Method - 생성 패턴, Template Method - 행동 패턴임을 참고하세요.
Parameterized
Parameterized Factory Method
매개변수 팩토리란 입력 매개변수에 따라 다른 클래스의 객체를 반환하는 기능을 말합니다.
대형 프로그램을 개발하다 보면 생각보다 많은 수의 객체를 생성해야 하기도 하고,
객체 관계 설정이 복잡해지고 객체 생성을 처리하는 코드 위치도 분산됩니다.
객체 생성을 한 곳에 집중해서 처리하면 유지 보수와 수정이 수월하겠죠?
팩토리 메서드에서 입력받은 매개변수를 처리할 때 매개변수에 맞는 클래스를 선택하여 객체를 생성합니다.
public abstract class Pizza {
public abstract decimal GetPrice();
public enum PizzaType {
HamMushroom, Deluxe, Seafood
}
public static Pizza PizzaFactory(PizzaType pizzaType) {
switch (pizzaType) {
case PizzaType.HamMushroom:
return new HamAndMushroomPizza();
case PizzaType.Deluxe:
return new DeluxePizza();
case PizzaType.Seafood:
return new SeafoodPizza();
}
throw new System.NotSupportedException("The pizza type " + pizzaType.ToString() + " is not recognized.");
}
}
enum PizzaType
을 정의하여 파라미터로 받아 객체를 구분해 반환하는 예제입니다.
Factory Method 특징
✔️ DIP, Dependency Inversion Principle.
의존 관계 역전의 원칙
Depend upon abstractions. Do not depend upon concrete classes
DIP는 구체화에 의존하지 말고 추상화에 의존하라는 원칙입니다.
Factory Method는 추상화된 객체를 정의해서 하위 클래스에서 구현하는 패턴을 보입니다.
Factory Method는 DIP 원칙을 잘 구현한 사례입니다.
✔️ 의존성
생성 패턴은 객체의 생성 과정을 외부에 공개하지 않기 위해 사용합니다.
직접적으로 new
키워드를 사용하는 빈도가 줄어들게 됩니다.
느슨한 결합으로 의존성을 줄일 수 있습니다.
✔️ 캡슐화와 관리
팩토리 메서드 패턴은 클래스 결합도가 낮고 유연성이 좋습니다. 또한, 기능 개선 시 기능을 보완하기 위한 리팩터링 작업도 편리하다는 장점을 지닙니다.
Factory Method 구조
Product (Document)
Factory method가 생성할 객체의 인터페이스를 정의합니다.
ConcreteProduct (MyDocument)
Factory method가 생성할 객체로, Product를 implements합니다.
Creator (Application)
Product(혹은 ConcreteProduct) 타입을 반환하는 Factory method를 정의합니다.
Product 객체를 만들기 위해 factory method를 호출할 수 있습니다.
ConcreteCreator (MyApplication)
ConcreteProduct의 인스턴스를 반환하는 factory method를 오버라이딩하여 구현합니다.
응용 예제
다양한 구조의 Document 객체를 만들고자 합니다.
예를 들어 Excel 문서나, PPT나 Pages와 같은 발표 문서 등을 제작한다고 가정해봅시다.
문서는 기본적으로 열고, 닫고, 저장하고, 복구시키는 동일한 기능을 가집니다. 그렇기 때문에 Document라는 Interface로 기본 정의를 만들어 코드의 중복을 줄이고 골격을 정의해 객체에 대한 이해를 쉽게 할 수 있도록 만듭니다.
이제 정해진 골격Document을 따라 실제 문서를 제작하고자 합니다. Factory Method는 new
연산자를 통해 직접 객체를 생성하지 않고 생성 객체(Factory)를 따로 정의해서 생성하기 때문에 Creator객체가 필요합니다.
public abstract class Document {
public abstract void open();
public abstract void close();
// ...
}
public class MyDocument extends Document {
// implementation of the abstract methods
}
문서를 다양한 형태로 제작하는 것을 목표로 하기 때문에 Creator를 추상화시킵니다. 추상 클래스를 적용하는 것은 객체를 생산하고 사용하는 것을 분리하기 위해서입니다. 이 부분은 Template Method를 이해하면 금방 와닿을 수 있을텐데요.
Application의 CreateDocument
는 추상 메소드입니다. 즉, 하위클래스인 MyApplication
에서 실제 구현을 해야만합니다.
Application의 NewDocument
에서 CreateDocumnet
를 실행하기 때문에 생산과 사용을 분리한다고 볼 수 있습니다.
public abstract class Application {
private List<Document> docs = new ArrayList<Document>();
public void newDocument() {
Document doc = createDocument();
docs.add(doc);
doc.open();
}
// factory method
public abstract Document createDocument();
}
public class MyApplication extends Application {
// factory method 구현부
public Document createDocument() {
return new TextDocument();
}
}
Sample Code: Java
코드는 Github 에서 확인하실 수 있습니다.
Product
public interface Product {
void name();
}
ConcreateProduct
class LgProduct implements Product {
public void name() {
System.out.println("LG Gram laptop");
}
}
class SamsungProduct implements Product {
public void name() {
System.out.println("Samsung Always laptop");
}
}
Creator
abstract class Factory {
public Product create(String model) {
return this.createProduct(model);
}
abstract public Product createProduct(String model);
}
ConcreteCreator
class ProductFactory extends Factory {
public ProductFactory() {
System.out.println("ProductFactory 생성");
}
public Product createProduct(String model) {
if (model == "LG") {
return new LgProduct();
} else {
return new SamsungProduct();
}
}
}
Main
public class Main {
public static void main(String[] args) {
Factory fac = new ProductFactory();
Product pro = fac.create("LG");
pro.name();
pro = fac.create("SAMSUNG");
pro.name();
}
}
관련 패턴
C- Creational Patterns | S - Structural Patterns | B - Behavioral Patterns
팩토리 메서드 패턴은 보통 하나의 객체로 사용하는데, 이를 위해 싱글턴 패턴 방식이나 정적 클래스로 구현합니다.
구현부에서 실체 객체를 생성할 때 싱글턴 페턴을 응용해 중복 생성을 방지할 수 있습니다.
복합체 패턴의 컴포넌트는 추상화되어 있습니다.
컴포넌트의 leaf와 composite는 다형성을 적용하여 구체적 행위가 하위 클래스로 위임되며, 컴포넌트 템플릿화되어 구현되지 않은 메서드를 호출해 사용할 수 있습니다. 추상화와 템플릿 처리 과정은 팩토리 템플릿과 유사한 구조로 되어 있습니다.
팩토리 메서드에서 골격과 생성을 분리할 때 템플릿 메서드 패턴을 응용하는 듯, 템플릿 메서드 패턴과 팩토리 메서드 패턴은 매우 밀접한 관계가 있습니다.
반복자 패턴은 메서드를 반복적으로 호출합니다.
반복해서 생성되는 객체가 있을 경우 팩토리 메서드 패턴을 함께 적용할 수 있습니다.
그럼 지금까지 Factory Method Pattern에 대해 알아보았습니다.
오타나 잘못된 내용이 있다면 댓글로 남겨주세요!
감사합니다 ☺️
'ETC > Design Patterns' 카테고리의 다른 글
Design Pattern, Proxy (0) | 2022.01.12 |
---|---|
Design Pattern, Abstract Factory (0) | 2022.01.05 |
Design Pattern, Template Method (0) | 2022.01.01 |
Design Pattern, Strategy (0) | 2021.12.29 |
Design Pattern, Builder (1) | 2021.12.29 |
Backend Software Engineer
𝐒𝐮𝐧 · 𝙂𝙮𝙚𝙤𝙣𝙜𝙨𝙪𝙣 𝙋𝙖𝙧𝙠