Stop Writing If-Else Spaghetti: Architecting Cleaner Java with the Strategy Pattern

DZone Java · 2026.07.24
Stop Writing If-Else Spaghetti: Architecting Cleaner Java with the Strategy Pattern

절차적 복잡성이 만들어내는 기술 부채

엔터프라이즈 Java 애플리케이션에서 비즈니스 로직은 시간이 지나면서 자연스럽게 복잡해지는 경향이 있다. 처음에는 단순한 할인 계산이나 금융 트랜잭션 평가로 시작했던 기능이, 어느 순간 수백 줄짜리 중첩 if-else와 취약한 switch 문으로 가득 찬 모놀리식 서비스 메서드로 변질된다.

이는 단순한 가독성 문제가 아니다. 이런 코드 구조는 단위 테스트를 극도로 어렵게 만들고, 객체지향 설계 원칙을 정면으로 위반한다. 더 심각한 건 회귀 위험이다. 새로운 비즈니스 규칙 하나를 추가하려다가 기존 규칙 세 개가 깨지는 상황이 반복된다면, 팀 전체의 배포 신뢰도는 급격히 떨어질 수밖에 없다.

// 전형적인 안티패턴
public double calculateDiscount(String customerType, double amount) {
    if (customerType.equals("VIP")) {
        if (amount > 1000) { return amount * 0.2; }
        else { return amount * 0.1; }
    } else if (customerType.equals("MEMBER")) {
        // ...
    } else if (customerType.equals("COUPON")) {
        // ...
    }
    return 0;
}

전략 패턴으로 책임 분리하기

전략 패턴(Strategy Pattern)은 이런 문제를 구조적으로 해결하는 GoF 디자인 패턴이다. 핵심 아이디어는 각 비즈니스 규칙을 독립된 전략 클래스로 캡슐화하고, 컨텍스트 객체가 이를 주입받아 실행하도록 위임하는 것이다. 조건 분기 로직이 단일 메서드에 집중되는 대신, 각 전략이 자신의 책임만 담당하게 된다.

// 전략 인터페이스 정의
public interface DiscountStrategy {
    double apply(double amount);
}

// 각 정책을 독립 클래스로 구현
public class VipDiscountStrategy implements DiscountStrategy {
    @Override
    public double apply(double amount) {
        return amount > 1000 ? amount * 0.2 : amount * 0.1;
    }
}

// 컨텍스트는 전략을 주입받아 실행
public class DiscountContext {
    private final DiscountStrategy strategy;

    public DiscountContext(DiscountStrategy strategy) {
        this.strategy = strategy;
    }

    public double calculate(double amount) {
        return strategy.apply(amount);
    }
}

Spring 환경에서는 각 전략 구현체를 @Component로 등록하고, Map<String, DiscountStrategy> 형태로 주입받아 런타임에 키 기반으로 전략을 선택하는 패턴을 많이 활용한다. 이 방식은 새로운 정책 추가 시 기존 코드를 전혀 수정하지 않아도 되므로 OCP(Open-Closed Principle)를 자연스럽게 충족한다.

실무에서 얻는 실질적 이점

전략 패턴의 가장 큰 실무적 가치는 테스트 용이성이다. 각 전략 클래스가 단일 책임만 갖기 때문에, 복잡한 통합 테스트 없이도 개별 비즈니스 규칙을 독립적으로 단위 테스트할 수 있다. 기존 모놀리식 구조에서는 특정 조건 조합을 테스트하기 위해 수많은 목(Mock)이 필요했다면, 전략 패턴 도입 후에는 전략 클래스 하나에 집중된 간결한 테스트가 가능해진다.

또한 팀 협업 관점에서도 효과적이다. 새로운 팀원이 특정 비즈니스 규칙을 파악할 때, 수백 줄의 메서드를 분석하는 대신 해당 전략 클래스 하나만 읽으면 된다. 기능 추가나 수정의 영향 범위가 명확해지므로 코드 리뷰와 배포 자신감도 함께 높아진다.

정리

  • if-else 중첩 구조는 가독성을 넘어 테스트 불가능성과 높은 회귀 위험이라는 심각한 기술 부채를 유발한다
  • 전략 패턴은 각 비즈니스 규칙을 독립 클래스로 캡슐화해 OCP를 충족하고, 단위 테스트를 극적으로 단순화한다
  • Spring 환경에서는 전략 구현체를 빈으로 등록하고 Map 주입으로 런타임 선택을 구현하면 확장성과 유지보수성을 동시에 확보할 수 있다
Source
DZone Java
원문 보기 →
← 목록으로 돌아가기