개요
최근 오랜만에 팩토리 패턴이라는 개념을 다시 듣게 되었는데, 어떤 개념이었는지 기억이 잘 나지 않아서 정리해 둔다.
Factory method pattern
객체 지향 디자인 패턴, 그중에서도 생성 패턴 중 하나이다.
객체를 생성하기 위한 인터페이스는 정의하되, 생성할 클래스는 서브 클래스가 결정하도록 한다. 다른 말로 인스턴스화를 서브 클래스에 연기하게 하는 방법이다.
객체를 생성하기 위해서는 종종 포함하기에 적절하지 않은 복잡한 프로세스가 필요할 수 있다. 때문에 팩토리 메서드 패턴은 객체 생성을 위한 별도의 방법을 정의하여 이러한 문제를 처리한다.
구조
- Product : 최상위 제품 클래스
- ConcreteProduct : 제품 구현체
- Creator : 최상위 팩토리 클래스. 추상화된 팩토리 메서드를 제공하여 서브 클래스가 구현하도록 한다.
- someOperation : 객체 생성 처리 메서드. 객체 생성과 관련된 전후처리를 템플릿 화한 메서드이다.
- createProduct : 서브 클래스에서 재정의할 객체 생성 메서드
- ConceteCreator : 서브 팩토리 클래스는 적절한 제품 객체를 반환하도록 추상화된 객체 생성 메서드를 재정의한다.
특징
장점
클래스 생성부와 구현 객체 간의 결합도를 낮출 수 있다.
객체 생성 코드를 한 곳으로 위치시켜 코드를 보다 쉽게 유지보수 할 수 있다. 즉, 단일 책임 원칙을 준수한다.
기존 코드를 수정하지 않고 새로운 구현 객체를 추가할 수 있으므로 개방/폐쇄 원칙을 준수한다.
단점
구현 객체마다 팩토리 객체를 구현해야 하므로 코드가 복잡해질 수 있다.
적용이 필요한 경우
- 코드가 함께 동작해야 하는 객체의 유형과 의존관계를 모를 때 사용할 수 있다.
팩토리 메서드는 제품 생성부와 실제 사용 코드를 분리하기 때문에 제품 생성부를 독립적으로 확장하기 좋다. 새 제품을 도입해야 하는 경우에는 팩토리 메서드만 재정의하면 되기 때문이다. - 라이브러리/프레임워크 사용자에게 구성 요소를 확장하는 방법을 제공하려고 할 때 사용할 수 있다.
- 기존 객체를 재구성하는 대신 기존 객체를 재사용하여 리소스를 재사용하고 싶을 때 사용할 수 있다.
예시
의사코드로 작성한 간단한 예시로 팩토리 메서드 패턴을 알아보자.
최상위 제품 클래스
최상위 제품 클래스는 모든 제품 구현체가 구현해야 하는 작업을 선언한다.
interface Button is
method render()
method onClick(f)
제품 구현체
제품 구현체는 최상위 제품 클래스에서 제공하는 인터페이스를 구현한다.
class WindowsButton implements Button is
method render(a, b) is
method onClick(f) is
class HTMLButton implements Button is
method render(a, b) is
method onClick(f) is
최상위 팩토리 클래스
최상위 팩토리 클래스는 팩토리 메서드를 선언해야 하고, 하위 팩토리 클래스는 부모 클래스에서 선언한 팩토리 메서드를 구현해야 한다.
class Dialog is
# 팩토리 메서드의 기본 구현 제공 가능
abstract method createButton():Button
method render() is
Button okButton = createButton()
okButton.onClick(closeDialog)
okButton.render()
또한 최상위 팩토리 클래스는 제품에 의존하는 핵심 비즈니스 로직을 포함할 수 있다.
서브 팩토리 클래스
제품 변경을 변경할 수 있도록 팩토리 클래스를 재정의한다.
class WindowsDialog extends Dialog is
method createButton():Button is
return new WindowsButton()
class WebDialog extends Dialog is
method createButton():Button is
return new HTMLButton()
사용
이제 팩토리 클래스를 사용하여 설정 환경 등에 따라 다른 유형의 클래스를 생성하여 사용할 수 있다.
class Application is
field dialog: Dialog
method initialize() is
config = readApplicationConfigFile()
if (config.OS == "Windows") then
dialog = new WindowsDialog()
else if (config.OS == "Web") then
dialog = new WebDialog()
else
throw new Exception("Error! Unknown operating system.")
this.initialize()
dialog.render()