디자인 패턴 & OOP

[디자인 패턴] 팩토리 메서드 패턴(Factory Method Pattern)

cloud-grace 2024. 5. 26. 00:54

팩토리 메서드 패턴(Factory Method Pattern)이란?

팩토리 메서드 패턴은 디자인 패턴(Design Pattern) 중 생성 패턴(Creational Pattern)이다.

생성 패턴 : 객체의 생성과 관련된 패턴이며, 객체의 생성 절차를 추상화하는 패턴
객체를 생성 및 합성하는 방법과 객체의 표현 방법과 시스템을 분리한다.

 
GoF 디자인 패턴에 의하면 팩토리 메서드 패턴은 객체 생성을 서브 클래스로 위임하여 캡슐화한다고 한다.
 

팩토리 메서드 패턴 : 객체를 생성하는 인터페이스를 정의하지만, 어떤 클래스의 인스턴스를 만들지는 서브 클래스가 결정하도록 하는 디자인 패턴이다. 따라서 서브 클래스에게 클래스 인스턴스 생성과 관련한 것을 맡긴다. 이는 객체 생성 코드를 캡슐화하고, 새로운 객체가 추가되더라도 기존 코드를 수정하지 않게 해준다. 즉, 종속성을 줄여준다.

 
팩토리 메서드 패턴은 객체를 생성하는 코드를 한 곳에 모아 두어 객체 생성 과정을 캡슐화하고, 객체 생성 과정을 숨길 경우에 사용한다. 또한, 기존 코드를 수정하지 않고 확장할 수 있는 확장성을 통해 개방-폐쇄 원칙을 준수한다. 코드 재사용성과 유지보수에 용이하며, 객체 생성 방법을 서브 클래스에서 정의하여 다양한 객체 생성 방식을 유연하게 처리할 수 있다.

팩토리 메서드 패턴 구조

출처 : pngwing

  • Creator : 객체를 생성하기 위한 인터페이스를 정의하며 최상위 공장 클래스이다.
    • factoryMethod() : 팩토리 메서드로 서브 공장 클래스에서 재정의할 객체 생성 추상 메서드이다.
    • anOperation() : 객체 생성을 처리하는 메서드로 객체 생성 전처리 및 후처리를 템플릿처럼 만든다.
  • ConcreteCreator : Creator 클래스를 상속 받아 팩토리 메서드를 구현하여 구체적인 Product 객체를 생성한다. 각 서브 공장 클래스에 맞는 Product 객체를 반환하도록 한다.
  • Product : 생성될 Product 구현체를 추상화한다.
  • ConcreateProduct : Product 구현체이며 구체적인 제품을 정의한다.

팩토리 메서드 패턴 예제 코드

  • Product 제품 인터페이스 정의
// Product interface
interface Product {
    void use();
}
  • ConcreteProduct 구체적인 제품 구현체 : Product 인터페이스 구현 및 각 제품별 로직을 구성한다.
// ConcreteProduct class
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA");
    }
}
// ConcreteProduct class
class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductB");
    }
}
  • Creator 최상위 공장 추상 클래스 : 외부에서 Product 생성할 때는 anOperation() 메서드 호출, 실제로 어떤 객체를 생성할 지는 추상 메서드(factoryMethod())로 정의해서 서브 클래스에서 정의한다. 또한, protected로 접근을 제한하고 싶을 때 사용한다.
// Creator Class
abstract class Creator {
    protected abstract Product factoryMethod();

    public void anOperation() {
        // Factory Method를 사용하여 객체를 생성
        Product product = factoryMethod();
        product.use();
    }
}
  • ConcreteCreator 공장 객체 반환 : Creator을 상속받아 각 제품별 객체를 반환하도록 오버라이드한다.
// ConcreteCreator class
class ConcreteCreatorA extends Creator {
    @Override
    public Product factoryMethod() {
        return new ConcreteProductA();
    }
}
// ConcreteCreator class
class ConcreteCreatorB extends Creator {
    @Override
    public Product factoryMethod() {
        return new ConcreteProductB();
    }
}
  • Client : ConcreteProduct에 대한 의존성 없이 사용 가능하다. 의존성 주입을 사용하여 외부의 Creator 클래스를 가져온다면 ConcreteCreator에 대한 의존성도 제거가 가능하다.
public class FactoryMethodPatternExample {
    public static void main(String[] args) {
        Creator creatorA = new ConcreteCreatorA();
        creatorA.someOperation();

        Creator creatorB = new ConcreteCreatorB();
        creatorB.someOperation();
    }
}

팩토리 메서드 패턴의 장점

  • 객체 생성 코드를 한 곳에 모아두어 재사용이 가능하다.
  • 객체 생성 로직을 서브 클래스에서 결정할 수 있어 유연하고 확장성이 높다.
  • 캡슐화 및 추상화로 객체 타입을 숨길 수 있다.
  • Creator과 ConcreteProduct 간의 강한 결합을 피할 수 있다.

팩토리 매서드 패턴의 단점

  • 클래스 수가 늘어나면 코드 구조가 복잡해진다.
  • 즉, 각 Product 구현체마다 Factory(Creator) 객체를 모두 구현해야 해서 구현체 증가 시 서브 클래스 수가 급증한다.