Mobile & App Stack/Java Software Architecture & Patterns

팩토리 메서드 패턴(Factory Method Pattern) 완벽 정리: 왜 사용할까? (Java 예제)

임베디드 친구 2024. 12. 20. 08:40
반응형

소프트웨어의 규모가 커질수록 객체를 생성하는 코드가 여기저기 흩어져 유지보수가 어려워지는 경우가 많습니다. 이때 객체 생성 로직을 분리하여 시스템의 결합도를 낮춰주는 팩토리 메서드 패턴(Factory Method Pattern)은 개발자에게 필수적인 도구입니다.

오늘은 이 패턴의 핵심 개념부터 실무에 적용 가능한 Java 예제까지 자세히 정리해 보겠습니다.

Generated by Gemini AI.


1. 팩토리 메서드 패턴이란?

팩토리 메서드 패턴은 객체 생성의 책임을 서브클래스로 위임하는 생성 패턴입니다.

쉽게 말해, 부모 클래스에서는 객체를 생성하는 인터페이스(메서드)만 정의하고, 어떤 클래스의 인스턴스를 만들지는 자식 클래스에서 결정하게 하는 방식입니다. 이를 통해 클라이언트 코드는 구체적인 클래스 이름 대신 인터페이스에만 의존하게 됩니다.

핵심 구성 요소

  1. Product (인터페이스): 생성될 객체의 공통 기능을 정의합니다.
  2. Concrete Product: 인터페이스를 실제로 구현한 구체적인 클래스입니다.
  3. Creator (추상 클래스): 객체를 생성하는 '팩토리 메서드'를 선언합니다.
  4. Concrete Creator: 팩토리 메서드를 오버라이드하여 실제 객체를 생성하고 반환합니다.

2. 왜 팩토리 메서드 패턴인가? (장점과 단점)

장점

  • 결합도 감소 (Decoupling): 클라이언트 코드가 구체적인 구현 클래스가 아닌 인터페이스에 의존하므로, 내부 로직이 변경되어도 영향을 받지 않습니다.
  • 개방-폐쇄 원칙(OCP) 준수: 기존 코드를 수정하지 않고도 새로운 종류의 제품(Product)을 추가할 수 있습니다.
  • 단일 책임 원칙(SRP) 강화: 객체 생성 로직을 한곳으로 모아 관리 효율성을 높입니다.

단점

  • 클래스 개수 증가: 새로운 제품을 추가할 때마다 제품 클래스와 생성자 클래스를 쌍으로 늘려야 하므로 코드의 양이 많아질 수 있습니다.

3. Java 구현 예제: 로그 시스템 만들기

이해를 돕기 위해 다양한 환경(파일, 콘솔, DB)에 로그를 남기는 시스템을 예로 들어보겠습니다.

Step 1. Product 정의

Java
 
// Product 인터페이스
interface Logger {
    void log(String message);
}

// ConcreteProduct 1
class ConsoleLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("[Console] " + message);
    }
}

// ConcreteProduct 2
class FileLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("[File] Writing to file: " + message);
    }
}

Step 2. Creator 정의

Java
 
// Creator 추상 클래스
abstract class LoggerFactory {
    // 팩토리 메서드
    public abstract Logger createLogger();

    // 팩토리 메서드를 사용하는 비즈니스 로직
    public void logMessage(String message) {
        Logger logger = createLogger();
        logger.log(message);
    }
}

// ConcreteCreator 1
class ConsoleLoggerFactory extends LoggerFactory {
    @Override
    public Logger createLogger() {
        return new ConsoleLogger();
    }
}

// ConcreteCreator 2
class FileLoggerFactory extends LoggerFactory {
    @Override
    public Logger createLogger() {
        return new FileLogger();
    }
}

Step 3. 클라이언트 코드 활용

Java
 
public class Main {
    public static void main(String[] args) {
        // 콘솔 로그 사용 시
        LoggerFactory consoleFactory = new ConsoleLoggerFactory();
        consoleFactory.logMessage("시스템이 시작되었습니다.");

        // 파일 로그 사용 시 (클라이언트 로직 수정 최소화)
        LoggerFactory fileFactory = new FileLoggerFactory();
        fileFactory.logMessage("에러가 발생하여 파일에 기록합니다.");
    }
}

4. 팩토리 메서드 패턴 vs 단순 팩토리 (Simple Factory)

많은 분이 헷갈려 하는 부분입니다.

  • 단순 팩토리: 하나의 클래스가 if-else나 switch 문으로 객체를 생성합니다. 새로운 타입 추가 시 팩토리 클래스 수정이 필요해 OCP에 어긋납니다.
  • 팩토리 메서드: 클래스 자체를 추상화하여 상속을 통해 확장합니다. 수정에는 닫혀 있고 확장에는 열려 있는 구조를 가집니다.

5. 결론: 언제 사용해야 할까?

객체 생성 로직이 복잡하거나, 앞으로 어떤 구체 클래스가 추가될지 모르는 유연한 구조가 필요할 때 팩토리 메서드 패턴은 최고의 선택입니다. 특히 프레임워크나 라이브러리를 설계할 때 사용자에게 확장 지점을 제공하는 용도로 널리 쓰입니다.

객체지향 설계의 깊이를 더하고 싶다면, 지금 바로 여러분의 프로젝트에 적용해 보시는 건 어떨까요?


글이 도움이 되셨다면 구독과 공감 부탁드립니다! 다음 포스팅에서는 이와 유사하지만 다른 추상 팩토리 패턴(Abstract Factory)에 대해 알아보겠습니다.

반응형