728x90
전략 패턴으로 if-else 걷어내기
결론부터
결제 수단이나 알림 채널처럼 종류가 늘어날 때마다 if-else/switch가 길어지는 코드는 전략 패턴의 신호다. 전략 패턴은 '무엇을 할지'를 인터페이스로 추상화하고, 각 경우를 별도 구현으로 분리한다. 스프링을 쓴다면 구현체들을 자동으로 모아 주입해 주기 때문에, 새 전략을 추가할 때 기존 코드를 건드리지 않아도 된다(개방-폐쇄 원칙).
문제: 늘어나는 분기
// 결제 수단이 추가될 때마다 이 메서드가 계속 자란다
public void pay(String type, int amount) {
if (type.equals("CARD")) {
// 카드 결제
} else if (type.equals("KAKAO")) {
// 카카오페이 결제
} else if (type.equals("TOSS")) {
// 토스 결제
} else {
throw new IllegalArgumentException("지원하지 않는 결제 수단");
}
}
새 수단이 생길 때마다 이 메서드를 수정해야 하고, 회귀 테스트도 통째로 다시 해야 한다.
해결: 전략 인터페이스
'무엇을 할지'를 인터페이스로 뽑는다.
public interface PaymentStrategy {
String type(); // 이 전략이 담당하는 수단
void pay(int amount);
}
각 결제 수단을 독립 구현으로 분리하고, 스프링 빈으로 등록한다.
@Component
public class CardPayment implements PaymentStrategy {
public String type() { return "CARD"; }
public void pay(int amount) { /* 카드 결제 */ }
}
@Component
public class KakaoPayment implements PaymentStrategy {
public String type() { return "KAKAO"; }
public void pay(int amount) { /* 카카오페이 결제 */ }
}
스프링이 조립을 대신한다
핵심은 여기다. 스프링은 같은 인터페이스의 구현체를 List나 Map으로 한꺼번에 주입해 준다.
@Service
public class PaymentService {
private final Map<String, PaymentStrategy> strategies;
// 스프링이 모든 PaymentStrategy 구현체를 모아 넣어 준다
public PaymentService(List<PaymentStrategy> list) {
this.strategies = list.stream()
.collect(Collectors.toMap(PaymentStrategy::type, s -> s));
}
public void pay(String type, int amount) {
PaymentStrategy strategy = strategies.get(type);
if (strategy == null) {
throw new IllegalArgumentException("지원하지 않는 결제 수단: " + type);
}
strategy.pay(amount);
}
}
이제 새 결제 수단은 PaymentStrategy를 구현한 @Component 하나만 추가하면 끝이다. PaymentService도, 기존 구현체도 손대지 않는다.
주의사항
- 전략이 2~3개로 고정이고 늘어날 일이 없다면, 굳이 패턴을 도입할 필요는 없다. 오히려 오버엔지니어링이 될 수 있다.
- 전략마다 상태를 갖지 않게(무상태) 설계해야 싱글턴 빈으로 안전하게 공유된다.
마무리
전략 패턴의 가치는 'if-else 제거' 자체가 아니라 확장 지점을 코드 수정 없이 여는 것이다. 스프링의 컬렉션 주입과 결합하면 분기문이 사라지고, 각 경우가 독립적으로 테스트 가능한 구조가 된다. 조건 분기가 계속 자라는 곳이 있다면 전략 패턴을 떠올려 보자.
728x90
'Programming > Design Pattern' 카테고리의 다른 글
| 어댑터 패턴 완벽 정리: Spring Boot 외부 API 연동을 분리하는 방법 (0) | 2026.07.29 |
|---|---|
| 옵저버 패턴, Spring ApplicationEvent로 실무에 써먹기 (0) | 2026.07.23 |
| 📌Java static vs Singleton 완벽 비교: 언제 어떤 걸 써야 할까? (1) | 2025.07.31 |
| ✅ PRG(Post-Redirect-Get) 패턴 – 새로고침 중복방지와 공유 가능한 웹 설계의 핵심 (1) | 2022.10.31 |
| ✅ [프록시 패턴 완벽 이해] 프록시 서버부터 UML, 활용 사례까지 총정리! (0) | 2022.10.30 |