1. 팩토리 패턴 (Factory Pattern) 이란?

객체 생성 과정팩토리 클래스로 분리하여 캡슐화하는 패턴

 

 

2. 특징

팩토리 클래스에 객체 생성을 선택하는 로직을 넣어 캡슐화

클라이언트에서는 팩토리 클래스로 객체를 구현하므로 어떤 구현체인지 별도 관리하지 않아도 됨

 

728x90

 

3. 사용 예시

특정 시점마다 세금 계산의 기준이 변경하여 계산해줄때

어떤 기준으로 계산할지를 정해주는 Factory Class 의 예시

 

기능

  • calculateTax(): 세금 계산

세금 계산 기능을 정의한 TaxCalculator Interface 를 생성한다.

interface TaxCalculator {
    double calculateTax(double amount);
}

 

 

버전 별 계산 기능 구현

  • TaxCalculatorV1: 세율 10% 로 계산
class TaxCalculatorV1 implements TaxCalculator {
    @Override
    public double calculateTax(double amount) {
        System.out.println("Using Tax Calculation Version 1");
        return amount * 0.1;
    }
}

 

  • TaxCalculatorV2: 세율 15% 로 계산
class TaxCalculatorV2 implements TaxCalculator {
    @Override
    public double calculateTax(double amount) {
        System.out.println("Using Tax Calculation Version 2");
        return amount * 0.15;
    }
}

 

 

 

팩토리 구현

  • 2025년 3월 28일 13시 이전 까지는 V1 (세율 10%) 로직 적용
  • 2025년 3월 28일 13시 부터는 V2 (세율 15%) 로직 적용
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

class TaxCalculatorFactory {
    private static final LocalDateTime VERSION_CHANGE_TIME = LocalDateTime.of(2025, 3, 28, 13, 0, 0, 0);

    public static TaxCalculator getTaxCalculator() {
        LocalDateTime currentTime = LocalDateTime.now();
        if (currentTime.isBefore(VERSION_CHANGE_TIME)) {
            return new TaxCalculatorV1();
        } else {
            return new TaxCalculatorV2();
        }
    }
}

 

 

사용 예시

public class Main {
    public static void main(String[] args) {
        double amount = 1000.0;
        TaxCalculator taxCalculator = TaxCalculatorFactory.getTaxCalculator();
        
        double tax = taxCalculator.calculateTax(amount); // console: Using Tax Calculation Version 2
        System.out.println("Calculated Tax: " + tax); // console: Calculated Tax: 150.0
    }
}

 

 

4. 장단점

장점

  1. 객체 생성 로직을 팩토리로 분리하여, 클라이언트가 객체 생성에 대한 세부 사항을 제어하지 않아도 됨
  2. 새로운 기준에 따른 구현체가 추가되어도 팩토리 클래스만 수정하면 되므로 코드의 확장성 뛰어남

단점

  1. 객체 생성 로직을 팩토리에서 관리하므로 경우에 따라 객체를 생성하는 방식에 대한 유연성이 제한

 

 

5. 결론

팩토리 패턴은 객체 생성 로직이 복잡하거나 다양한 구현체가 필요할 때 유용함.

객체 생성 방식을 클라이언트 코드에서 분리하고 캡슐화하여 코드의 확장성과 유연성을 높일 수 있음.

객체 생성이 단순하고 변하지 않으면 굳이 팩토리 패턴 사용하지 않고 명시적으로 사용하는게 가독성에 좋음.

728x90
반응형

'디자인패턴' 카테고리의 다른 글

[디자인 패턴] 상태 패턴 (State Pattern)  (0) 2025.03.04

1. 상태 패턴 (State Pattern) 이란?

상태에 따라 다른 행위를 할 때 상태객체화 하여 각각 다른 행동을 처리할 수 있게 하는 패턴

 

 

2. 특징

 

 

기능을 캡슐화 한 Interface와 각 상태 또는 상황 별 Class 로 이루어져 있고

상태 별로 기능을 구현하여 사용한다.

 

728x90

 

3. 사용 예시

문 열기, 문 닫기, 문 잠그기, 문 잠금해제하기 4가지의 기능이 있는 기계가 있을 때

현재 문의 상태에 따라서 기능이 달라 질 수 있다.

 

기능

  • open(): 문을 여는 행동
  • close(): 문을 닫는 행동
  • lock(): 문을 잠그는 행동
  • unlock(): 문을 잠금 해제하는 행동

기능을 정의한 DoorState Interface 를 생성한다.

interface DoorState {
    void open(Door door);
    void close(Door door);
    void lock(Door door);
    void unlock(Door door);
}

 

문의 상태를 관리하고 행동을 실행할 Door Class 를 생성한다.

class Door {
    private DoorState state;

    public Door() {
        this.state = new ClosedState(); // 초기 상태는 닫힌 상태
    }

    public void setState(DoorState state) {
        this.state = state;
    }

    public void open() {
        state.open(this);
    }

    public void close() {
        state.close(this);
    }

    public void lock() {
        state.lock(this);
    }

    public void unlock() {
        state.unlock(this);
    }
}

 

 

상태

  • ClosedState: 문이 닫혀있는 상태
  • OpenedState: 문이 열린 상태
  • LockedState: 문이 잠긴 상태

문이 닫힌 상태 Class 를 생성하고 닫힌 상태에서 기능 별 동작을 구현한다.

open() -> 현재 상태 문 열림으로 변경

close() -> 상태 변화X (이미 닫혀 있음)

lock() -> 현재 상태 문 잠김으로 변경

unlock() -> 상태 변화X (잠겨 있지 않음)

class ClosedState implements DoorState {
    @Override
    public void open(Door door) {
        System.out.println("문을 엽니다.");
        door.setState(new OpenedState());
    }

    @Override
    public void close(Door door) {
        System.out.println("문은 이미 닫혀 있습니다.");
    }

    @Override
    public void lock(Door door) {
        System.out.println("문을 잠급니다.");
        door.setState(new LockedState());
    }

    @Override
    public void unlock(Door door) {
        System.out.println("문은 잠겨 있지 않습니다.");
    }
}

 

 

문이 열린 상태 Class 를 생성하고 닫힌 상태에서 기능 별 동작을 구현한다.

open() -> 상태 변화X (이미 열려 있음)

close() -> 현재 상태 문 닫힘으로 변경

lock() -> 상태 변화X (문 열려 있어 잠글 수 없음)

unlock() -> 상태 변화X (잠겨 있지 않음)

class OpenedState implements DoorState {
    @Override
    public void open(Door door) {
        System.out.println("문은 이미 열려 있습니다.");
    }

    @Override
    public void close(Door door) {
        System.out.println("문을 닫습니다.");
        door.setState(new ClosedState());
    }

    @Override
    public void lock(Door door) {
        System.out.println("문은 열려 있어 잠글 수 없습니다.");
    }

    @Override
    public void unlock(Door door) {
        System.out.println("문은 잠겨 있지 않습니다.");
    }
}

 

 

문이 잠긴 상태 Class 를 생성하고 닫힌 상태에서 기능 별 동작을 구현한다.

open() -> 상태 변화X (잠겨 있어 열 수 없음)

close() -> 상태 변화X (이미 닫혀 있음)

lock() -> 상태 변화X (이미 잠겨 있음)

unlock() -> 현재 상태 문 닫힘으로 변경

class LockedState implements DoorState {
    @Override
    public void open(Door door) {
        System.out.println("문이 잠겨 있어 열 수 없습니다.");
    }

    @Override
    public void close(Door door) {
        System.out.println("문은 이미 닫혀 있습니다.");
    }

    @Override
    public void lock(Door door) {
        System.out.println("문은 이미 잠겨 있습니다.");
    }

    @Override
    public void unlock(Door door) {
        System.out.println("문을 잠금 해제합니다.");
        door.setState(new ClosedState());
    }
}

 

 

사용 예시

public class Main {
    public static void main(String[] args) {
        Door door = new Door();

        // 문 열기
        door.open(); // console: 문을 엽니다.

        // 문 닫기
        door.close(); // console: 문을 닫습니다.

        // 문 잠그기
        door.lock(); // console: 문을 잠급니다.

        // 문 열기 시도 (잠금 상태)
        door.open(); // console: 문이 잠겨 있어 열 수 없습니다.

        // 문 잠금 해제
        door.unlock(); // console: 문을 잠금 해제합니다.

        // 다시 문 열기
        door.open(); // console: 문을 엽니다.
    }
}

 

 

4. 장단점

장점

  1. 상태 별 행동을 명확히 분리할 수 있음
  2. 상태가 변경될 때마다 자동으로 상태에 맞는 동작이 실행되므로 일관성 있음

단점

  1. 상태가 많아지면 상태 클래스가 많아져 코드가 과도하게 복잡해 질 수 있음

 

 

5. 결론

상태 패턴은 상태 전환이 빈번하고 각 상태에 따른 행동이 달라야 하는 시스템에서 유용하게 사용 할 수 있음.

상태별로 동작을 캡슐화하고 관리할 수 있어 유지보수가 편리해지고 확장성이 높다는 장점이 있으나

상태 전환이 단순하거나 상태가 적은 경우에는 오히려 이 패턴을 적용하는 것이 과도할 수 있음

728x90
반응형

'디자인패턴' 카테고리의 다른 글

[디자인 패턴] 팩토리 패턴 (Factory Pattern)  (0) 2025.03.28

+ Recent posts