팩토리 패턴

Bo Ram·2025년 3월 18일

1. 팩토리 패턴이란?

팩토리 패턴(Factory Pattern)은 객체 생성 로직을 캡슐화하여, 객체 생성을 담당하는 별도의 클래스를 제공하는 디자인 패턴이다.
이 패턴을 사용하면 객체를 생성하는 코드와 사용하는 코드를 분리할 수 있어 유지보수성이 향상된다.

2. 팩토리 패턴의 특징

  • 객체 생성 로직을 숨긴다 → 클라이언트가 직접 객체를 생성하지 않고, 팩토리 클래스를 통해 생성한다.
  • 유연성과 확장성 증가 → 새로운 객체 타입이 추가되더라도 기존 코드 수정 없이 확장할 수 있다.
  • 결합도를 낮춘다 → 객체 생성과 사용을 분리하여 코드의 재사용성을 높인다.

팩토리 패턴의 다양한 구현 방식

1. 단순 팩토리(Simple Factory)

가장 기본적인 형태의 팩토리 패턴으로, 팩토리 메서드를 통해 객체를 생성한다.

class Product {
    void use() {
        System.out.println("제품 사용");
    }
}

class ConcreteProductA extends Product {
    @Override
    void use() {
        System.out.println("A 제품 사용");
    }
}

class ConcreteProductB extends Product {
    @Override
    void use() {
        System.out.println("B 제품 사용");
    }
}

// 팩토리 클래스
class SimpleFactory {
    public static Product createProduct(String type) {
        if (type.equals("A")) {
            return new ConcreteProductA();
        } else if (type.equals("B")) {
            return new ConcreteProductB();
        }
        throw new IllegalArgumentException("Unknown product type: " + type);
    }
}

// 사용 예시
public class FactoryPatternExample {
    public static void main(String[] args) {
        Product product = SimpleFactory.createProduct("A");
        product.use();
    }
}

특징

  • 객체 생성을 팩토리 클래스에서 관리하여 클라이언트 코드가 구체적인 클래스를 알 필요가 없다.
  • 단점: 새로운 제품이 추가될 때마다 createProduct() 메서드를 수정해야 한다.

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

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

// 제품 인터페이스
interface Product {
    void use();
}

// 구체적인 제품 클래스
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("A 제품 사용");
    }
}

class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("B 제품 사용");
    }
}

// 팩토리 인터페이스
abstract class Factory {
    abstract Product createProduct();

    public void doSomething() {
        Product product = createProduct();
        product.use();
    }
}

// 구체적인 팩토리 클래스
class ConcreteFactoryA extends Factory {
    @Override
    Product createProduct() {
        return new ConcreteProductA();
    }
}

class ConcreteFactoryB extends Factory {
    @Override
    Product createProduct() {
        return new ConcreteProductB();
    }
}

// 사용 예시
public class FactoryMethodExample {
    public static void main(String[] args) {
        Factory factory = new ConcreteFactoryA();
        factory.doSomething(); // "A 제품 사용"
    }
}

특징

  • 객체 생성 로직이 팩토리 메서드(createProduct())에 캡슐화된다.
  • 새로운 제품이 추가될 때 팩토리 클래스를 수정하지 않고, 새로운 팩토리 클래스를 만들면 된다.
  • 단점: 클래스 수가 많아질 수 있다.

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

추상 팩토리 패턴은 서로 관련된 객체군을 생성하는 인터페이스를 제공하는 방식이다.

// 제품 인터페이스
interface ProductA {
    void use();
}

interface ProductB {
    void interact();
}

// 제품 구현 클래스
class ConcreteProductA1 implements ProductA {
    @Override
    public void use() {
        System.out.println("A1 제품 사용");
    }
}

class ConcreteProductA2 implements ProductA {
    @Override
    public void use() {
        System.out.println("A2 제품 사용");
    }
}

class ConcreteProductB1 implements ProductB {
    @Override
    public void interact() {
        System.out.println("B1 제품과 상호작용");
    }
}

class ConcreteProductB2 implements ProductB {
    @Override
    public void interact() {
        System.out.println("B2 제품과 상호작용");
    }
}

// 추상 팩토리
interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// 구체적인 팩토리 클래스
class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}

class ConcreteFactory2 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}

// 사용 예시
public class AbstractFactoryExample {
    public static void main(String[] args) {
        AbstractFactory factory = new ConcreteFactory1();
        ProductA productA = factory.createProductA();
        ProductB productB = factory.createProductB();

        productA.use();
        productB.interact();
    }
}

특징

  • 제품군을 묶어서 생성할 수 있다.
  • 클라이언트는 특정 제품이 아니라 팩토리를 통해 객체를 생성하므로, 제품을 교체할 때 코드 수정이 적다.
  • 단점: 새로운 제품군이 추가되면 모든 팩토리 클래스를 수정해야 한다.

팩토리 패턴을 사용할 때 고려해야 할 점

1. 리플렉션(Reflection) 활용 가능

팩토리 패턴에서는 Class.forName()을 사용하여 동적으로 객체를 생성할 수도 있다.

public class DynamicFactory {
    public static Product createProduct(String className) {
        try {
            return (Product) Class.forName(className).getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("제품 생성 실패", e);
        }
    }
}

장점

  • 새로운 클래스가 추가될 때 코드 변경 없이 객체를 생성할 수 있다.
    단점
  • 리플렉션을 사용하면 성능 저하가 발생할 수 있다.

2. Spring에서의 팩토리 패턴

Spring에서는 팩토리 패턴을 직접 구현하지 않고, 스프링 컨테이너가 제공하는 Bean 관리 기능을 활용하는 것이 일반적이다.

  • @Bean, @Component, @Service 등을 사용하면 Spring이 객체 생성을 관리한다.
  • 직접 팩토리 패턴을 구현하는 것보다 DI(의존성 주입)를 활용하는 것이 더 좋은 경우가 많다.

팩토리 패턴의 활용

  1. Spring의 Bean Factory

    • Spring의 BeanFactory는 팩토리 패턴을 기반으로 객체를 관리한다.
  2. 데이터베이스 드라이버

    • JDBC의 DriverManager.getConnection()은 팩토리 패턴을 사용하여 적절한 DB 드라이버를 제공한다.
  3. 로깅 시스템

    • LoggerFactory.getLogger(Class<?>)는 팩토리 패턴을 활용한 대표적인 예시다.

결론

팩토리 패턴은 객체 생성을 캡슐화하여 유연성을 높이는 강력한 패턴이다.
하지만 Spring과 같은 프레임워크에서는 직접 구현하기보다 프레임워크가 제공하는 기능을 활용하는 것이 더 효율적이다.
팩토리 패턴을 올바르게 사용하면 유지보수성과 확장성을 높일 수 있다.

profile
사부작ㅤ사부작

0개의 댓글