프로그래밍/디자인패턴

팩토리 패턴(Factory Pattern) 총정리

Jinwookoh 2025. 12. 7. 17:33

객체 지향 프로그래밍에서 new 키워드를 사용하여 객체를 직접 생성하는 것은 가장 흔한 작업이지만, 동시에 강한 결합(Coupling) 을 유발하는 원인이기도 합니다.

Java
// 나쁜 예: 클라이언트가 구체적인 클래스에 의존함
Car car = new Sonata(); 

 

이 결합도를 낮추기 위해 "객체 생성을 전담하는 공장(Factory)" 을 만드는 것이 팩토리 패턴의 핵심입니다. 하지만 팩토리 패턴은 구현 복잡도에 따라 크게 3단계로 나뉩니다. 오늘은 그 차이를 명확히 정리해 보겠습니다.


1. 심플 팩토리 (Simple Factory)

엄밀히 말하면 GoF 디자인 패턴에는 포함되지 않는 관용구(Idiom)지만, 실무에서 가장 많이 쓰입니다. 단순히 객체 생성 로직을 별도의 클래스로 떼어낸 형태입니다.

특징

  • static 메서드를 사용하여 입력값에 따라 다른 객체를 반환합니다.
  • 클라이언트는 팩토리 클래스 하나만 알면 됩니다.

코드 예시

Java
 
public class CarFactory {
    // static 메서드로 간단하게 구현
    public static Car createCar(String type) {
        if ("SONATA".equals(type)) {
            return new Sonata();
        } else if ("GRANDEUR".equals(type)) {
            return new Grandeur();
        }
        throw new IllegalArgumentException("Unknown car type");
    }
}

// 사용 (Client)
Car myCar = CarFactory.createCar("SONATA");

장단점

  • 장점: 구현이 매우 쉽고, 클라이언트 코드가 깔끔해집니다.
  • 단점: 새로운 차종(Genesis)이 추가되면 CarFactory의 if-else 문을 수정해야 하므로 OCP(개방-폐쇄 원칙)를 위반합니다.

2. 팩토리 메서드 패턴 (Factory Method Pattern)

GoF에서 정의하는 정석적인 패턴입니다. **"객체 생성을 서브 클래스에게 위임"**하는 방식입니다.

특징

  • 부모 클래스(인터페이스)는 "객체를 생성한다"는 메서드(create)만 정의하고, 실제 어떤 객체를 만들지는 자식 클래스가 결정합니다.
  • 상속(Inheritance) 구조를 활용합니다.

코드 예시

Java
 
// 1. 추상 팩토리 (Creator)
public abstract class CarFactory {
    // 팩토리 메서드 (구현은 자식이 함)
    abstract Car createCar();

    // 공통 로직 (템플릿 메서드처럼 활용 가능)
    public void deliverCar() {
        Car car = createCar();
        car.drive();
    }
}

// 2. 구체적 팩토리 (Concrete Creator)
public class SonataFactory extends CarFactory {
    @Override
    Car createCar() {
        return new Sonata();
    }
}

public class GenesisFactory extends CarFactory {
    @Override
    Car createCar() {
        return new Genesis();
    }
}

장단점

  • 장점: 새로운 차종이 추가되어도 기존 코드를 수정할 필요 없이 GenesisFactory만 새로 만들면 됩니다. (OCP 준수)
  • 단점: 관리해야 할 클래스 파일의 개수가 늘어납니다.

3. 추상 팩토리 패턴 (Abstract Factory Pattern)

가장 복잡한 형태입니다. 단순히 객체 하나가 아니라, **"관련된 객체들의 집합(Family)"**을 생성해야 할 때 사용합니다.

상황 예시

  • 윈도우(Windows) 스타일: WinButton, WinScrollbar
  • 맥(Mac) 스타일: MacButton, MacScrollbar
  • 이 부품들은 서로 섞이면 안 되고 세트로 다녀야 합니다.

코드 예시

Java
 
// 1. 추상 팩토리 (모든 부품을 만드는 공장 인터페이스)
public interface GUIFactory {
    Button createButton();
    Scrollbar createScrollbar();
}

// 2. 윈도우용 공장
public class WindowsFactory implements GUIFactory {
    public Button createButton() { return new WinButton(); }
    public Scrollbar createScrollbar() { return new WinScrollbar(); }
}

// 3. 맥용 공장
public class MacFactory implements GUIFactory {
    public Button createButton() { return new MacButton(); }
    public Scrollbar createScrollbar() { return new MacScrollbar(); }
}

장단점

  • 장점: 제품군(Family) 간의 교체가 매우 쉽습니다. (new WindowsFactory()를 new MacFactory()로만 바꾸면 모든 UI가 변경됨)
  • 단점: 새로운 부품 종류(예: TextField)가 추가되면, 모든 Factory 인터페이스와 구현체를 수정해야 하는 대공사가 일어납니다.

요약: 어떤 팩토리를 선택해야 할까?

패턴 종류 핵심 개념 구현 방식 추천 상황
Simple Factory 생성 로직 캡슐화 static 메서드 + if-else 생성할 객체 종류가 적고 변경이 거의 없을 때
Factory Method 생성 책임 위임 추상 메서드 + 상속 객체 생성 로직을 확장 가능하게(OCP) 만들고 싶을 때
Abstract Factory 제품군(Family) 생성 인터페이스 + 조합 OS별 테마, DB별 접속 모듈 등 관련된 객체들을 한 번에 바꿔야 할 때

결론

대부분의 실무 비즈니스 로직에서는 Simple FactoryFactory Method 선에서 해결되는 경우가 많습니다.

  • Spring Framework를 사용하신다면 BeanFactory나 ApplicationContext가 이미 팩토리 패턴의 거대한 구현체입니다.
  • 직접 구현할 때는 무조건 복잡한 추상 팩토리를 쓰기보다, Simple Factory로 시작해서 필요할 때 Factory Method로 리팩토링하는 접근을 추천합니다.