[CS] 디자인 패턴 #2 팩토리 패턴

Youngshin Park·2025년 2월 23일

CS

목록 보기
2/5

팩토리 패턴

💡 간단 설명:
구체적인 클래스 이름을 직접 명시하지 않고도 객체를 생성할 수 있도록 하는 방법
즉, 객체 생성 로직을 별도의 팩토리 클래스로 분리하여, 클라이언트 코드에서는 어떤 구체적인 객체가 생성되는지 알 필요 없이 인터페이스나 추상 클래스를 통해 객체를 사용할 수 있게 해줌

팩토리 패턴이란, 객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴이자 상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 객체 생성에 관한 구체적인 내용을 결정하는 패턴이다.

  • 상위 클래스와 하위 클래스가 분리되기 때문에 느슨한 결합을 가지고, 상위 클래스에서는 인스턴스 생성 방식에 대해 전혀 알 필요가 없기 때문에 더 많은 유연성을 갖게 된다.
  • 또한, 객체 생성 로직이 따로 떼어져 있어 코드를 리팩토링하더라도 한 곳만 고칠 수 있게 되어 유지 보수성이 증가한다.

주요 특징

1️⃣ 객체 생성의 책임 분리
객체를 생성하는 코드를 팩토리 클래스에 모아두어, 객체 생성 방식이 변경되더라도 클라이언트 코드에 영향을 주지 않는다.

2️⃣ 코드의 유연성과 확장성 향상
새로운 종류의 객체가 추가되더라도 팩토리 클래스를 수정하거나 확장하면 되므로, 클라이언트 코드는 변경 없이 그대로 유지할 수 있다.

3️⃣ 의존성 감소
클라이언트는 구체적인 클래스에 의존하지 않고 추상적인 인터페이스나 추상 클래스를 사용하므로, 코드 결합도가 낮아진다.


더 이해하기 위해 예를 들어보자. 자동차(Car)라는 인터페이스를 구현하는 여러 종류의 자동차(예: 스포츠카, 세단 등)가 있다고 가정할 때, 팩토리 패턴을 이용하면 클라이언트는 어떤 종류의 자동차가 생성되는지 몰라도 자동차 객체를 사용할 수 있다. 팩토리 클래스는 요청에 따라 적절한 자동차 객체를 생성하여 반환하게 된다.

자바스크립트의 팩토리 패턴

자바스크립트에서 구현한다면 간단하게 new Object()를 이용할 수 있다.

const num = new Object(42)
const str = new Object('abc')
num.constructor.name; // Number
str.constructor.name; // String

숫자를 전달하거나 문자열을 전달함에 따라 다른 타입의 객체를 생성한다.
즉, 전달받은 값에 따라 다른 객체를 생성하고 인스턴스의 타입 등을 정하는 것이다.

커피 팩토리를 기반으로 라떼를 생상하는 코드를 작성해보았다.

class CoffeeFactory {
    static createCoffee(type) {
        const factory = factoryList[type]
        return factory.createCoffee()
    }
}   
class Latte {
    constructor() {
        this.name = "latte"
    }
}
class Espresso {
    constructor() {
        this.name = "Espresso"
    }
} 

class LatteFactory extends CoffeeFactory{
    static createCoffee() {
        return new Latte()
    }
}
class EspressoFactory extends CoffeeFactory{
    static createCoffee() {
        return new Espresso()
    }
}
const factoryList = { LatteFactory, EspressoFactory } 
 
 
const main = () => {
    // 라떼 커피를 주문한다.  
    const coffee = CoffeeFactory.createCoffee("LatteFactory")  
    // 커피 이름을 부른다.  
    console.log(coffee.name) // latte
}
main()

CoffeeFacotry라는 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스인 LatteFactory가 구체적인 내용을 결정한다.
위 코드는 의존성 주입이라고 볼 수 있다.

  • CoffeeFactory에서 LatteFactory의 인스턴스를 생성하는 것이 아닌 후자에서 생성한 인스턴스를 전자에 주입하고 있기 때문이다.

자바의 팩토리 패턴

자바에서는 주로 추상 클래스나 인터페이스를 이용해 팩토리 패턴을 구현한다. 아래 예제는 커피 팩토리 패턴을 이용해 커피 객체를 생성하는 과정을 보여준다.

enum CoffeeType {
    LATTE,
    ESPRESSO
}

abstract class Coffee {
    protected String name;

    public String getName() {
        return name;
    }
}

class Latte extends Coffee {
    public Latte() {
        name = "latte";
    }
}

class Espresso extends Coffee {
    public Espresso() {
        name = "Espresso";
    }
}

class CoffeeFactory {
    public static Coffee createCoffee(CoffeeType type) {
        switch (type) {
            case LATTE:
                return new Latte();
            case ESPRESSO:
                return new Espresso();
            default:
                throw new IllegalArgumentException("Invalid coffee type: " + type);
        }
    }
}

public class Main {
    public static void main(String[] args) { 
        Coffee coffee = CoffeeFactory.createCoffee(CoffeeType.LATTE); 
        System.out.println(coffee.getName()); // latte
    }
}

CoffeeFacotry 밑에 Coffee 클래스르 놓고 해당 클래스를 상속하는 Latte, Espresso 클래스를 기반으로 구현한 모습이다.
코드를 보충 설명해보면 다음과 같다.
1. 추상화된 객체 생성: Coffee라는 추상 클래스를 통해 공통 인터페이스를 정의하고, 이를 상속받은 Latte와 Espresso 클래스에서 구체적인 객체를 구현한다.
2. 스위치 문을 통한 분기 처리: CoffeeFactory 클래스의 createCoffee 메서드는 전달된 CoffeeType에 따라 적절한 커피 객체를 생성한다.
3. 확장성: 새로운 커피 종류가 추가될 경우, Coffee를 상속하는 새로운 클래스를 만들고, CoffeeFactory에 해당 타입에 대한 분기만 추가하면 되므로 클라이언트 코드는 수정할 필요가 없게 된다.


팩토리 패턴은 객체 생성의 복잡도를 줄이고, 코드 재사용성과 확장성을 크게 향상시키는 효과적인 디자인 패턴이다.




** 모든 코드는 https://github.com/wnghdcjfe/csnote/tree/main/ch1 에서 참고하였습니다.

1개의 댓글

comment-user-thumbnail
2025년 2월 26일

열공 머쪄요

답글 달기