Strategy Pattern가 내 Spring 시스템의 결제 로직을 단순화한 방법

발행: (2026년 2월 4일 오전 10:40 GMT+9)
5 min read
원문: Dev.to

Source: Dev.to

이 글에서는 소프트웨어 아키텍처의 실제 문제를 해결한 디자인 패턴에 대해 살펴보겠습니다: 응답에 반환된 결제 유형에 따라 요청을 처리하기 위해 특정 실행 패턴을 적용해야 하는 필요성. 신용카드, PayPal 등 각 결제 수단마다 별도의 동작을 수행해야 했습니다.

두드러진 해결책은 **전략 패턴(Strategy Design Pattern)**의 적용이었습니다. 이 패턴은 각 처리 로직을 자체 클래스(‘전략’)로 분리할 수 있게 해 주어 코드가 더 깔끔하고 유지보수가 용이하며, 무엇보다도 향후 새로운 결제 수단이 추가될 경우에도 높은 확장성을 제공합니다.

참고: 여기서 제시하는 코드는 실제 환경을 단순화한 것이며, 핵심은 아키텍처 솔루션의 본질에 있습니다.

처리 인터페이스 정의

첫 번째 단계는 모든 결제 전략에 대한 공통 계약을 설정하는 것이었습니다. PaymentProcessor 인터페이스를 만들었으며, 이는 각 전문 처리 클래스에서 구현될 메서드를 정의합니다.

public interface PaymentProcessor {
    boolean process(final PaymentResponse request);
}

전략을 관리하는 서비스

다음으로, 우리는 솔루션의 핵심인 PaymentService 클래스를 만들었습니다. 이 클래스의 책임은 PaymentProcessor 인터페이스의 모든 구현을 매핑하고 관리하는 것입니다. 이를 통해 각 실행 유형에 대해 어떤 클래스가 담당하는지 식별할 수 있습니다. 예시에서는 PayPal과 Credit Card 전략을 시작했습니다. 지원되는 유형의 품질과 엄격한 관리를 보장하기 위해 PaymentType이라는 Enum을 사용했으며, 향후 Debit Card와 같은 새로운 방식의 추가 또는 제거를 쉽게 할 수 있습니다.

@Service
public class PaymentService {
    private Map processors;

    public PaymentService(@Qualifier("paypal") PaymentProcessor paypal,
                          @Qualifier("credit_card") PaymentProcessor credit) {
        processors = Map.of(PaymentType.PAYPAL, paypal, PaymentType.CREDIT_CARD, credit);
    }

    public boolean process(String type, PaymentResponse request) {
        PaymentType paymentType = PaymentType.valueOf(type.toUpperCase());
        PaymentProcessor processor = processors.get(paymentType);
        if (Objects.isNull(processor)) {
            throw new IllegalArgumentException("Type not supported: " + type);
        }
        return processor.process(request);
    }
}
public enum PaymentType {
    PAYPAL, CREDIT_CARD, DEBIT_CARD
}

결제 전략 구현

이제 PayPalProcessorCreditCardProcessor 클래스를 만들었습니다. 두 클래스 모두 PaymentProcessor 인터페이스를 구현합니다. Spring Boot 프레임워크를 사용하여 이 클래스들을 어노테이션으로 표시하면, 애플리케이션이 시작될 때 프레임워크가 이를 식별하고 Bean을 올바르게 관리하여 PaymentService에 주입할 수 있습니다. 이렇게 하면 PaymentService는 모든 전략을 매핑하고 바로 사용할 준비가 됩니다.

@Component
@Qualifier("paypal")
public class PayPalProcessor implements PaymentProcessor {
    @Override
    public boolean process(PaymentResponse request) {
        System.out.println("✅ PayPal processed!");
        return true;
    }
}
@Component
@Qualifier("credit_card")
public class CreditCardProcessor implements PaymentProcessor {
    @Override
    public boolean process(PaymentResponse request) {
        System.out.println("✅ credit card processed!");
        return true;
    }
}

실행과 IF의 종료

우리는 중요한 단계에 도달했습니다: 실행 단계입니다. 우리는 PaymentResponse(다른 API들의 반환을 시뮬레이션) 를 받으며, 그 안의 paymentType 필드가 어떤 종류의 결제인지를 알려줍니다. PaymentService가 작동하여 정보를 직접 처리합니다. 여기서 큰 장점은 조건문(if/else 또는 switch/case)을 사용해 결제 유형을 확인할 필요가 없다는 점입니다.

Spring Boot의 빈 관리 덕분에, 요청이 들어올 때 PaymentService는 단순히 전달된 paymentType에 해당하는 전략을 요청하고 올바른 메서드를 실행합니다. 이 접근 방식은 유지보수성을 향상시킬 뿐만 아니라 안전 모드를 보장하려고 하며, Java에서 흔히 발생하는 NullPointerException과 같은 오류를 예방합니다.

Back to Blog

관련 글

더 보기 »