전략패턴이란?
- 동일한 작업을 수행하는 여러 알고리즘(전략)을 인터페이스로 정의하고, 이를 런타임에 교체할 수 있게 해주는 디자인 패턴
- 알고리즘을 캡슐화하고 유연하게 교체할 수 있는 구조를 제공하여 코드의 유지보수성과 확장성을 크게 향상
전략패턴의 특징
- 알고리즘 캡슐화: 알고리즘을 인터페이스로 추상화하고, 이를 여러 클래스에서 각각 구현
- 런타임 교체 가능: 런타임에 전략을 변경할 수 있음
- 유지보수성 향상: 조건문을 줄이고 새로운 전략을 쉽게 추가 가능
- 클라이언트 코드와 알고리즘 분리: 클라이언트는 알고리즘 구현에 대해 알 필요 없이 인터페이스만 사용
전략 패턴의 구성 요소
- Strategy(전략 인터페이스) : 알고리즘을 정의하는 인터페이스
- ConcreteStrategy(구체적인 전략 클래스) : 전략 인터페이스를 구현하고, 각각의 알고리즘을 캡슐화한 클래스
- Context(문맥 클래스) :전략을 사용하는 클래스. 전략 객체를 생성자나 세터 메서드로 주입받아 사용
사용 예 : 결제 시스템
1. 전략 인터페이스 정의
public interface PaymentStrategy {
void pay(int amount);
}
2. 구체적인 전략 클래스 정의
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("카드로 결제합니다.");
}
}
public class BankTransferPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("계좌이체를 통해 결제합니다.");
}
}
3. 문맥 클래스 정의 : 실제 전략 클래스를 멤버변수로 두어 사용하는 클래스
구성을 통해 전략 클래스를 사용한다. (구성 : A는 B를 가지고 있다.)
public class PaymentContext {
private PaymentStrategy paymentStrategy;
// 전략을 생성자를 통해 주입받음
public PaymentContext(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
// 전략을 변경할 수 있도록 세터 메서드 제공
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void pay(int amount) {
paymentStrategy.pay(amount);
}
}
4. 클라이언트에서 코드 사용
public class StrategyPatternExample {
public static void main(String[] args) {
// 1. Credit Card 결제 전략 사용
PaymentContext context = new PaymentContext(new CreditCardPayment());
context.pay(100);
// 2. Bank Transfer 결제 전략으로 변경 (런타임 환경에서 전략 변경 가능)
context.setPaymentStrategy(new BankTransferPayment());
context.pay(300);
}
}
전략패턴 사용 장단점
전략 패턴의 장점
- 알고리즘 교체가 쉬움: 새로운 알고리즘을 추가해도 기존 코드에 영향을 주지 않음
- 조건문 제거: if-else 또는 switch문을 대체하여 코드 가독성 향상
- 유지보수 용이: 알고리즘이 독립된 클래스로 캡슐화되어, 수정이 쉽고 재사용성이 높음
- 유연성: 런타임에 전략을 교체할 수 있어 상황에 맞게 다르게 동작할 수 있음
전략 패턴의 단점
- 클래스 수 증가: 각 전략을 독립적인 클래스로 정의해야 하므로, 클래스 수가 많아질 수 있음
- 전략 선택 책임: 클라이언트가 적절한 전략을 선택해야 하며, 전략 선택 로직이 복잡해질 수 있음
- 단순한 경우에는 오버엔지니어링: 간단한 조건문을 대체하기 위해 사용할 경우 코드가 불필요하게 복잡해질 수 있음
전략 패턴을 적용하면 좋은 실제 사례
- 로깅 전략: 다양한 로깅 방식(Console, File, Database 등)을 선택적으로 사용해야 할 때
- 데이터 압축: ZIP, RAR, GZIP 등 다양한 압축 방식을 런타임에 교체할 때
- 파일 변환: CSV, JSON, XML 등의 포맷 변환을 지원해야 할 때