Design Pattern
Strategy Pattern
창욱씨
2024. 1. 10. 21:35
반응형
Strategy Pattern (전략 패턴)
개념
Strategy Pattern은 행위(Behavioral) 디자인 패턴 중 하나로, 알고리즘군을 정의하고 각각을 캡슐화하여 교환 가능하게 만드는 패턴입니다. 클라이언트 코드를 변경하지 않고도 런타임에 알고리즘을 자유롭게 교체할 수 있습니다.
핵심 원칙
"변하는 것을 캡슐화하라" — 변경되는 부분(알고리즘)을 인터페이스 뒤에 숨기고, 변경되지 않는 부분(컨텍스트)과 분리한다.
구조

classDiagram
class Context {
-strategy: Strategy
+setStrategy(Strategy)
+executeStrategy()
}
class Strategy {
<<interface>>
+execute()
}
class ConcreteStrategyA {
+execute()
}
class ConcreteStrategyB {
+execute()
}
class ConcreteStrategyC {
+execute()
}
Context --> Strategy
Strategy <|.. ConcreteStrategyA
Strategy <|.. ConcreteStrategyB
Strategy <|.. ConcreteStrategyC
| 구성 요소 | 역할 |
|---|---|
| Strategy (인터페이스) | 알고리즘의 공통 인터페이스 정의 |
| ConcreteStrategy | 실제 알고리즘 구현체 |
| Context | Strategy 객체를 보유하고, 클라이언트에게 알고리즘 실행을 위임 |
예시: 결제 시스템
// 1. Strategy 인터페이스
public interface PaymentStrategy {
void pay(int amount);
}
// 2. 구체적인 전략들
public class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
public CreditCardPayment(String cardNumber) {
this.cardNumber = cardNumber;
}
@Override
public void pay(int amount) {
System.out.println(amount + "원을 신용카드로 결제합니다.");
}
}
public class KakaoPayPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println(amount + "원을 카카오페이로 결제합니다.");
}
}
public class NaverPayPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println(amount + "원을 네이버페이로 결제합니다.");
}
}
// 3. Context
public class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}
// 4. 클라이언트 코드
public class Main {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
// 런타임에 전략 교체 가능!
cart.setPaymentStrategy(new CreditCardPayment("1234-5678"));
cart.checkout(50000);
cart.setPaymentStrategy(new KakaoPayPayment());
cart.checkout(30000);
}
}
Strategy Pattern을 안 쓰면?
// ❌ if-else 지옥 — OCP(개방-폐쇄 원칙) 위반
public void pay(String type, int amount) {
if (type.equals("credit")) {
// 신용카드 결제 로직
} else if (type.equals("kakao")) {
// 카카오페이 결제 로직
} else if (type.equals("naver")) {
// 네이버페이 결제 로직
}
// 새 결제 수단 추가 시 이 메서드를 계속 수정해야 함!
}
장점과 단점
| 장점 | 단점 |
|---|---|
| ✅ OCP 준수 — 새 전략 추가 시 기존 코드 수정 불필요 | ❌ 전략이 적으면 오버엔지니어링이 될 수 있음 |
| ✅ 런타임 교체 — 실행 중 알고리즘 변경 가능 | ❌ 클라이언트가 구체적인 전략의 차이를 알아야 함 |
| ✅ 조건문 제거 — if/else, switch 분기 제거 | ❌ 전략 클래스 수가 증가할 수 있음 |
| ✅ 테스트 용이 — 각 전략을 독립적으로 테스트 가능 |
실무에서의 활용 사례
- 정렬 알고리즘 교체 —
Collections.sort(list, comparator)에서Comparator가 Strategy - 인증 방식 — JWT, OAuth, Session 등 인증 전략 교체
- 파일 압축 — ZIP, GZIP, LZ4 등 압축 알고리즘 선택
- 로깅 — Console, File, DB 등 로깅 대상 전환
- 할인 정책 — 정액 할인, 정률 할인, 쿠폰 할인 등
관련 패턴과의 차이
| 패턴 | 차이점 |
|---|---|
| Template Method | 상속 기반으로 알고리즘 골격을 정의. Strategy는 위임(composition) 기반 |
| State | 구조는 유사하나, State는 상태 전이에 초점. Strategy는 알고리즘 교체에 초점 |
| Factory | 객체 생성에 관한 패턴. Strategy는 객체의 행위에 관한 패턴 |
반응형