2) Strategy 패턴: 알고리즘을 런타임에 교체

“알고리즘을 캡슐화하고 교체 가능하게 만듦”

2-1) 문제 상황

// ❌ 할인 정책이 하드코딩됨
public class OrderService {
    public int calculateDiscount(Order order, String customerType) {
        if (customerType.equals("VIP")) {
            return order.getAmount() * 20 / 100;  // 20% 할인
        } else if (customerType.equals("REGULAR")) {
            return order.getAmount() * 10 / 100;  // 10% 할인
        } else {
            return 0;
        }
    }
}

문제점:

  • 새 할인 정책 추가 시 기존 코드 수정
  • 할인 로직 재사용 불가
  • 테스트 어려움

2-2) Strategy 패턴 적용

// Strategy 인터페이스
public interface DiscountStrategy {
    int calculate(int amount);
}

// 구체 전략들
public class VipDiscountStrategy implements DiscountStrategy {
    @Override
    public int calculate(int amount) {
        return amount * 20 / 100;
    }
}

public class RegularDiscountStrategy implements DiscountStrategy {
    @Override
    public int calculate(int amount) {
        return amount * 10 / 100;
    }
}

public class NoDiscountStrategy implements DiscountStrategy {
    @Override
    public int calculate(int amount) {
        return 0;
    }
}

// Context (전략 사용)
public class Order {
    private int amount;
    private DiscountStrategy discountStrategy;

    public Order(int amount, DiscountStrategy discountStrategy) {
        this.amount = amount;
        this.discountStrategy = discountStrategy;
    }

    public void setDiscountStrategy(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public int getFinalAmount() {
        int discount = discountStrategy.calculate(amount);
        return amount - discount;
    }
}

// ✅ 사용
Order vipOrder = new Order(10000, new VipDiscountStrategy());
System.out.println(vipOrder.getFinalAmount());  // 8000

Order regularOrder = new Order(10000, new RegularDiscountStrategy());
System.out.println(regularOrder.getFinalAmount());  // 9000

// 런타임에 전략 변경 가능
vipOrder.setDiscountStrategy(new NoDiscountStrategy());
System.out.println(vipOrder.getFinalAmount());  // 10000

2-3) 실전 예제: 정렬 전략

public interface SortStrategy<T> {
    void sort(List<T> list);
}

public class QuickSortStrategy<T extends Comparable<T>> implements SortStrategy<T> {
    @Override
    public void sort(List<T> list) {
        // 퀵 정렬 구현
        Collections.sort(list);
    }
}

public class MergeSortStrategy<T extends Comparable<T>> implements SortStrategy<T> {
    @Override
    public void sort(List<T> list) {
        // 병합 정렬 구현
    }
}

public class DataProcessor<T extends Comparable<T>> {
    private SortStrategy<T> sortStrategy;

    public DataProcessor(SortStrategy<T> sortStrategy) {
        this.sortStrategy = sortStrategy;
    }

    public void process(List<T> data) {
        sortStrategy.sort(data);
        System.out.println("Sorted: " + data);
    }
}

// 사용
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);
DataProcessor<Integer> processor = new DataProcessor<>(new QuickSortStrategy<>());
processor.process(numbers);

2-4) Spring에서의 Strategy 패턴

// Strategy 인터페이스
public interface NotificationStrategy {
    void send(String message);
}

// 구현체들
@Component("emailNotification")
public class EmailNotificationStrategy implements NotificationStrategy {
    @Override
    public void send(String message) {
        System.out.println("Email: " + message);
    }
}

@Component("smsNotification")
public class SmsNotificationStrategy implements NotificationStrategy {
    @Override
    public void send(String message) {
        System.out.println("SMS: " + message);
    }
}

// Context
@Service
public class NotificationService {
    private final Map<String, NotificationStrategy> strategies;

    public NotificationService(List<NotificationStrategy> strategyList) {
        this.strategies = strategyList.stream()
            .collect(Collectors.toMap(
                s -> s.getClass().getSimpleName(),
                s -> s
            ));
    }

    public void notify(String type, String message) {
        NotificationStrategy strategy = strategies.get(type + "NotificationStrategy");
        if (strategy != null) {
            strategy.send(message);
        }
    }
}

📚 다음 편: 준비 중입니다.


👈 이전 편: 디자인 패턴 필수 (Part 1: 기초 패턴)