전략 패턴 (Strategy Pattern)
한눈에 보기
같은 문제를 푸는 여러 알고리즘을 클래스로 캡슐화해 런타임에 교체할 수 있게 하는 행위 패턴이다. 조건문 분기를 타입 확장으로 바꾸는 원리와 상태 패턴과의 차이를 다룬다.
최종 업데이트 2026.09.17
전략 패턴(Strategy Pattern)은 동일한 문제를 푸는 여러 알고리즘을 각각 별도의 클래스로 캡슐화하고, 이들을 런타임에 서로 교체할 수 있게 만드는 행위 디자인 패턴이다. 전략 패턴을 적용하면 알고리즘을 사용하는 코드와 알고리즘의 구체 구현이 분리되어, 조건문 분기 없이 새로운 알고리즘을 추가하거나 실행 중에 동작을 바꿀 수 있다. 결제 수단 선택, 할인 정책, 정렬 기준 지정처럼 "같은 일을 여러 방식으로" 해야 하는 곳에 두루 쓰인다.
패턴의 의도
기능은 같은데 방식만 다른 로직이 늘어나면 코드에는 보통 if-else나 switch 분기가 자란다. 배송비 계산이 일반, 프리미엄, 무료 회원마다 다르다면 계산 메서드 안에 회원 등급 분기가 생기고, 등급이 추가될 때마다 그 메서드를 다시 열어 수정해야 한다. 분기가 여러 메서드에 흩어지면 수정 누락 위험은 더 커진다.
전략 패턴의 의도는 "변하는 알고리즘 부분"을 인터페이스 뒤로 밀어내는 것이다. GoF의 첫 번째 설계 원칙인 "변하는 것을 찾아내어 변하지 않는 것과 분리하고 캡슐화하라"를 가장 직접적으로 구현한 패턴이라고 할 수 있다. 알고리즘 계열을 하나의 인터페이스로 정의하고 각 방식을 구현 클래스로 만들면, 사용하는 쪽(컨텍스트)은 인터페이스에만 의존한다. 어떤 전략을 쓸지는 외부에서 주입하므로 알고리즘의 선택과 사용이 분리되고, 분기문은 타입 계층으로 대체된다.
구조와 참여 객체
- 전략(Strategy): 알고리즘 계열의 공통 인터페이스다. 컨텍스트가 호출할 메서드를 선언한다.
- 구체 전략(Concrete Strategy): 인터페이스를 구현한 개별 알고리즘이다.
- 컨텍스트(Context): 전략 객체를 필드로 보관하고, 작업이 필요할 때 전략에 위임한다. 어떤 구체 전략인지는 알지 못한다.
- 클라이언트(Client): 상황에 맞는 구체 전략을 골라 컨텍스트에 주입한다.
핵심은 전략 선택의 책임이 컨텍스트 밖(클라이언트나 설정, 팩토리)에 있다는 점이다. 컨텍스트 안에서 전략을 고르는 분기를 넣어 버리면 패턴을 적용한 의미가 반감된다. 전략에 필요한 데이터를 전달하는 방식은 두 가지가 있는데, 컨텍스트가 메서드 인자로 필요한 값만 넘기는 방식과 컨텍스트 자신을 통째로 넘기는 방식이다. 전자는 결합이 낮고 후자는 유연하지만 전략이 컨텍스트 내부를 알게 되므로, 기본적으로는 인자 전달 방식을 먼저 고려하는 것이 좋다.
Java 코드 예시
// 전략 인터페이스
public interface ShippingStrategy {
int calculateFee(int orderAmount);
}
// 구체 전략들
public class StandardShipping implements ShippingStrategy {
public int calculateFee(int orderAmount) {
return orderAmount >= 50000 ? 0 : 3000;
}
}
public class PremiumShipping implements ShippingStrategy {
public int calculateFee(int orderAmount) {
return 0; // 프리미엄 회원은 항상 무료
}
}
// 컨텍스트: 전략에 위임만 한다
public class ShippingCalculator {
private ShippingStrategy strategy;
public ShippingCalculator(ShippingStrategy strategy) {
this.strategy = strategy;
}
public void changeStrategy(ShippingStrategy strategy) {
this.strategy = strategy; // 런타임 교체
}
public int fee(int orderAmount) {
return strategy.calculateFee(orderAmount);
}
}
// 클라이언트가 전략을 선택해 주입
ShippingCalculator calc = new ShippingCalculator(new StandardShipping());
calc.fee(30000); // 3000
calc.changeStrategy(new PremiumShipping());
calc.fee(30000); // 0
전략 인터페이스의 메서드가 하나뿐이면 함수형 인터페이스이므로 Java 8 이후에는 람다로 간결하게 쓸 수 있다. JDK의 Comparator가 정확히 이 형태다. list.sort(Comparator.comparing(User::getAge))에서 정렬 알고리즘(컨텍스트)은 고정이고 비교 기준(전략)만 갈아 끼우는 것이 전략 패턴의 실사용 사례다.
장단점과 사용 시점
장점은 알고리즘 추가가 기존 코드 수정 없이 이루어진다는 것이다. 새 배송 정책은 클래스 하나를 추가하면 끝이므로 개방 폐쇄 원칙을 지키고, 각 알고리즘이 독립 클래스라서 단위 테스트도 개별적으로 할 수 있다. 실행 중에 전략을 바꿀 수 있다는 유연함도 상속 기반 방식이 주지 못하는 이점이다.
단점은 알고리즘 수만큼 클래스가 늘어난다는 점, 그리고 클라이언트가 전략들의 차이를 알고 적절히 골라야 한다는 점이다. 전략 개수가 고정적이고 각 전략이 상태를 갖지 않는다면 enum의 상수별 메서드 구현으로 전략 계층을 압축하는 방법도 있어, 클래스 폭발 문제를 상당히 완화할 수 있다. 알고리즘이 두어 개뿐이고 앞으로 늘 가능성도 없다면 단순 분기가 오히려 읽기 쉽다. 전략이 필요한 신호는 명확하다. 같은 목적의 분기문이 여러 곳에 반복되거나, 런타임에 동작을 바꿔야 하거나, 알고리즘의 세부 구현을 사용하는 쪽에서 감추고 싶을 때다. Spring에서 같은 인터페이스의 빈 여러 개를 Map으로 주입받아 요청 파라미터에 따라 골라 쓰는 방식도 전략 패턴의 전형적인 실무 활용이다.
유사 패턴과 비교
| 구분 | 전략(Strategy) | 템플릿 메서드(Template Method) | 상태(State) |
|---|---|---|---|
| 변경 메커니즘 | 합성(객체 주입) | 상속(메서드 오버라이드) | 합성(상태 객체 교체) |
| 교체 시점 | 런타임에 자유롭게 | 컴파일 타임에 고정 | 상태 전이 규칙에 따라 내부에서 |
| 바꾸는 대상 | 알고리즘 전체 | 알고리즘의 일부 단계 | 상태에 따른 행동 전체 |
| 누가 교체하는가 | 클라이언트(외부) | 교체 없음(하위 클래스 선택) | 상태 객체 자신 또는 컨텍스트 |
상태 패턴은 클래스 다이어그램이 전략과 거의 같아 자주 비교된다. 차이는 의도에 있다. 전략은 클라이언트가 알고리즘을 골라 주는 것이고, 상태는 객체 내부 상태에 따라 행동이 스스로 바뀌며 상태 객체들이 서로 전이를 알고 있는 경우가 많다. 또 전략들은 서로의 존재를 몰라도 되지만, 상태들은 다음 상태로의 전이 규칙 때문에 서로를 참조하는 일이 흔하다는 점도 구분 기준이 된다.
면접에서 이렇게 물어본다
- 전략 패턴이 if-else 분기 확장의 문제를 어떻게 해결하는지 설명해 보라.
- 전략 패턴과 템플릿 메서드 패턴의 차이를 합성과 상속의 관점에서 비교해 보라.
- JDK나 Spring에서 전략 패턴이 쓰인 사례를 들어 보라.
- 전략 패턴과 상태 패턴은 구조가 거의 같은데 무엇이 다른가.
- 전략 클래스가 많아지는 단점을 람다나 enum으로 어떻게 완화할 수 있는가.
디자인 패턴에서 같이 읽기
- 어댑터 패턴 (Adapter Pattern)호환되지 않는 인터페이스를 클라이언트가 기대하는 형태로 변환해 함께 동작하게 만드는 구조 패턴이다. 타깃, 어댑티, 어댑터, 클라이언트의 협력 구조와 장단점, 유사 패턴과의 차이를 정리한다.
- 어댑터 패턴 Java 구현 (Adapter Pattern in Java)InputStreamReader, Arrays.asList 등 JDK 속 어댑터 사례를 살펴보고, 클래스 어댑터와 객체 어댑터 두 구현 변형의 차이와 Java에서 객체 어댑터가 선호되는 이유를 정리한다.
- 컴포지트 패턴 (Composite Pattern)개별 객체와 객체 묶음을 같은 인터페이스로 다루어 트리 구조를 표현하는 구조 패턴이다. 파일과 폴더 예시 코드로 재귀 구조를 설명하고 투명성과 안전성의 트레이드오프를 다룬다.
- 디자인 패턴 개요 (GoF Design Patterns)반복되는 설계 문제의 검증된 해결 구조인 디자인 패턴을 GoF의 생성, 구조, 행위 세 분류로 조망한다. 패턴 선택 기준과 오남용 경계, 면접 대비 학습 전략까지 정리한다.
이 개념, 내 코드에서는 어떻게 물어볼까요
데브핏(DevFit)에 채용공고 URL을 붙여 넣고 레포지토리를 연결하면, 내가 쓴 커밋에서 예상 질문과 어필 포인트를 만듭니다. 하루 10회까지 무료입니다. 합불 판정이나 지원자 랭킹은 만들지 않고, 최종 판단은 사람이 합니다.
공고 넣고 시작하기