전략 패턴?
실행 중에 알고리즘 전략을 선택하여 객체 동작을 실시간으로 바뀌도록 할 수 있게 하는 행동 패턴
핵심 아이디어
- 동일한 문제를 해결하는 여러 알고리즘이 있을 때, 각 알고리즘을 별도의 클래스로 캡슐화
- 런타임에 알고리즘을 선택하여 교체 가능
- 조건문(if-else, switch) 대신 객체 위임을 통한 알고리즘 선택
구조

실무 예제: Java Comparator
public class ComparatorExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Alice", "Bob", "Charlie");
// 전략 1: 알파벳 순 정렬
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
System.out.println("알파벳 순: " + names);
// 전략 2: 길이 순 정렬
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
});
System.out.println("길이 순: " + names);
// 전략 3: 역순 정렬 (람다 사용)
names.sort((s1, s2) -> s2.compareTo(s1));
System.out.println("역순: " + names);
}
}
전략 패턴 적용 원리
- Strategy 인터페이스: Comparator<T>
- ConcreteStrategy: 각각의 익명 클래스 또는 람다 표현식
- Context: Collections.sort() 또는 List.sort() 메서드
정렬이라는 동일한 작업을 수행하지만, 비교 기준(알고리즘)을 런타임에 교체할 수 있다.
직접 구현: 쇼핑몰 결제 시스템
쇼핑몰에서 다양한 결제 수단을 지원하는 시스템을 전략 패턴으로 구현해보았다.
1. Strategy 인터페이스
public interface PaymentStrategy {
void pay(int amount);
}
2. ConcreteStrategy 구현
// 마스터 카드 결제 전략
public class MasterCardStrategy implements PaymentStrategy {
private String name;
private String cardNumber;
private String cvv;
public MasterCardStrategy(String name, String cardNumber, String cvv) {
this.name = name;
this.cardNumber = cardNumber;
this.cvv = cvv;
}
@Override
public void pay(int amount) {
System.out.println(amount + " Won paid using Master Card");
}
}
// 모바일 결제 전략
public class MobilePayStrategy implements PaymentStrategy {
private String email;
private String password;
public MobilePayStrategy(String email, String password) {
this.email = email;
this.password = password;
}
@Override
public void pay(int amount) {
System.out.println(amount + " Won paid using Mobile Pay");
}
}
3. Context 클래스
public class Item {
private String name;
private int price;
public Item(String name, int price) {
this.name = name;
this.price = price;
}
public int getPrice() {
return price;
}
}
public class ShoppingCart {
private List<Item> items;
private PaymentStrategy paymentStrategy;
public ShoppingCart() {
this.items = new ArrayList<>();
}
public void addItem(Item item) {
this.items.add(item);
}
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void pay() {
int amount = 0;
for (Item item : items) {
amount += item.getPrice();
}
this.paymentStrategy.pay(amount);
}
}
4. Client 코드
public class Client {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
cart.addItem(new Item("Macbook Pro", 10000));
cart.addItem(new Item("IPhone", 2000));
// 전략 1: 마스터 카드로 결제
cart.setPaymentStrategy(new MasterCardStrategy("Dmori", "1234-1234-1234-1234", "123"));
cart.pay();
// 전략 2: 모바일 페이로 결제
cart.setPaymentStrategy(new MobilePayStrategy("example@naver.com", "12345"));
cart.pay();
}
}
5. 실행 결과
12000 Won paid using Master Card
12000 Won paid using Mobile Pay
장단점
전략 패턴의 장점
- 개방-폐쇄 원칙(OCP): 새로운 결제 수단을 추가할 때 기존 코드를 수정하지 않고 새로운 전략 클래스만 추가하면 된다.
- 단일 책임 원칙(SRP): 각 결제 방식의 로직이 독립적인 클래스로 분리되어 있다.
- 런타임 유연성: 실행 중에 전략을 동적으로 교체할 수 있다.
- 테스트 용이성: 각 전략을 독립적으로 테스트할 수 있다.
- 조건문 제거: 복잡한 if-else나 switch 문을 객체로 대체할 수 있다.
전략 패턴의 단점
- 클래스 증가: 전략마다 별도의 클래스가 필요하므로 클래스 개수가 증가한다.
- 클라이언트의 인지: 클라이언트가 각 전략의 차이를 알아야 적절한 전략을 선택할 수 있다.
- 과도한 설계: 알고리즘이 하나뿐이거나 변경 가능성이 낮으면 오버엔지니어링이 될 수 있다.
전략 패턴 vs 상태 패턴
많은 사람들이 전략 패턴과 상태 패턴을 혼동하는데, 중요한 차이가 있다:
| 구분 | 전략 패턴 | 상태 패턴 |
| 목적 | 알고리즘 교체 | 상태에 따른 행동 변경 |
| 전환 | 클라이언트가 명시적으로 전략 선택 | 상태가 자동으로 전이됨 |
| 관계 | 전략들은 독립적 | 상태들은 서로 연관됨 |
| 예시 | 결제 수단 선택 | 노트북 전원 상태 |
마무리
전략 패턴은 알고리즘의 변경이 빈번하거나 여러 알고리즘 중 하나를 선택해야 하는 상황에서 매우 유용한 디자인 패턴이다.
Java의 Comparator처럼 실무에서도 널리 사용되고 있으며, 코드의 유연성과 확장성을 크게 향상시킬 수 있다.
구현 코드:
'Architecture > Design Pattern' 카테고리의 다른 글
| [Design Pattern] 싱글톤 (Singleton) 패턴이란? (0) | 2025.12.01 |
|---|