반응형
전략 패턴 (Strategy Pattern)
1. 정의
전략 패턴(Strategy Pattern)은 행위를 클래스 외부에서 캡슐화하여 동적으로 행위를 변경할 수 있도록 설계하는 디자인 패턴입니다. 즉, 특정 작업을 수행하는 여러 알고리즘이나 행동들이 있을 때, 이들을 개별 클래스로 캡슐화하고 필요에 따라 서로 교체하여 사용할 수 있게 하는 패턴입니다.
전략 패턴에서는 행위를 정의하는 인터페이스를 만들고, 이 인터페이스를 구현한 여러 개의 구체적인 전략 클래스를 정의합니다. 클라이언트는 이 전략 클래스들 중 하나를 선택하여 사용하며, 행위를 변경할 필요가 있을 때는 전략을 교체할 수 있습니다.
2. 목적
- 동적인 알고리즘 변경: 실행 중에 전략(알고리즘)을 교체할 수 있게 하여 유연성을 높입니다.
- 코드 중복 제거: 다양한 알고리즘을 캡슐화하여 코드 중복을 줄이고 유지보수를 용이하게 합니다.
- 객체 간 결합도 감소: 전략을 외부에서 주입받아 사용하므로, 클라이언트는 특정 전략에 의존하지 않고 다양한 전략을 유연하게 사용할 수 있습니다.
3. 사용 예시
전략 패턴은 다음과 같은 경우에 유용합니다:
- 여러 개의 알고리즘이 서로 교체 가능해야 하는 경우
- 코드에서 조건문(
if-else
나switch-case
)을 사용하여 여러 알고리즘을 선택하는 구조가 있을 때 - 런타임에 알고리즘을 변경하거나 선택할 수 있어야 할 때
4. 구현 방법
전략 패턴은 일반적으로 행동을 정의하는 인터페이스와 이를 구현하는 구체적인 전략 클래스들, 그리고 전략을 사용하는 컨텍스트 클래스로 구성됩니다.
// 1. 전략 인터페이스
interface PaymentStrategy {
void pay(int amount);
}
// 2. 구체적인 전략 클래스들
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
public CreditCardPayment(String cardNumber) {
this.cardNumber = cardNumber;
}
@Override
public void pay(int amount) {
System.out.println(amount + " paid using Credit Card: " + cardNumber);
}
}
class PaypalPayment implements PaymentStrategy {
private String email;
public PaypalPayment(String email) {
this.email = email;
}
@Override
public void pay(int amount) {
System.out.println(amount + " paid using PayPal: " + email);
}
}
// 3. 컨텍스트 클래스 (전략을 사용하는 클래스)
class ShoppingCart {
private List<String> items;
private PaymentStrategy paymentStrategy;
public ShoppingCart() {
this.items = new ArrayList<>();
}
public void addItem(String item) {
items.add(item);
}
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}
// 4. 클라이언트 코드
public class StrategyPatternDemo {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
cart.addItem("Item1");
cart.addItem("Item2");
// 결제 전략을 설정하고 사용
cart.setPaymentStrategy(new CreditCardPayment("1234-5678-9012-3456"));
cart.checkout(100); // 100 paid using Credit Card: 1234-5678-9012-3456
// 결제 전략을 PayPal로 변경하고 사용
cart.setPaymentStrategy(new PaypalPayment("user@example.com"));
cart.checkout(200); // 200 paid using PayPal: user@example.com
}
}
5. 동작 설명
- PaymentStrategy 인터페이스는 다양한 결제 방법을 정의한 전략 인터페이스입니다.
- CreditCardPayment와 PaypalPayment는 각각 신용카드 결제와 페이팔 결제를 처리하는 구체적인 전략 클래스들입니다.
- ShoppingCart 클래스는 클라이언트가 사용할 컨텍스트로,
PaymentStrategy
객체를 주입받아checkout()
메서드를 호출할 때 선택한 결제 전략을 실행합니다. - 클라이언트는 실행 중에 결제 전략을 동적으로 변경할 수 있으며, 코드 구조에 영향을 주지 않고 다양한 결제 방식으로 쉽게 확장 가능합니다.
6. 장점
- 알고리즘을 선택적으로 사용: 클라이언트는 특정 알고리즘에 의존하지 않고 실행 중에 다양한 알고리즘(전략)을 선택하고 변경할 수 있습니다.
- 코드 유지보수 용이: 각 알고리즘을 별도의 클래스에서 캡슐화하므로 코드의 가독성이 높고 유지보수가 용이합니다.
- 결합도 감소: 클라이언트는 구체적인 전략에 의존하지 않으며, 전략을 인터페이스로 추상화하여 유연한 설계를 제공합니다.
7. 단점
- 클래스가 많아짐: 전략 패턴을 사용하면 각 알고리즘마다 새로운 클래스를 작성해야 하므로, 클래스가 많아지고 코드가 복잡해질 수 있습니다.
- 전략을 변경해야 하는 책임: 클라이언트가 적절한 전략을 선택하거나 변경해야 하는 책임이 있으므로, 클라이언트가 전략 변경에 대한 지식을 가지고 있어야 합니다.
8. 전략 패턴이 유용한 경우
- 다양한 알고리즘이 필요할 때: 알고리즘이 다양하게 제공되며, 상황에 따라 어떤 알고리즘을 사용할지 동적으로 결정해야 하는 경우.
- 알고리즘이 자주 변경될 때: 새로운 알고리즘을 쉽게 추가하거나 기존 알고리즘을 교체해야 할 때.
- 조건문으로 알고리즘을 분기하는 코드가 있을 때:
if-else
나switch-case
와 같은 조건문이 많은 코드를 전략 패턴으로 리팩토링하면 코드의 복잡성을 줄일 수 있습니다.
9. 실제 사용 사례
- 정렬 알고리즘 선택:
Arrays.sort()
와 같은 라이브러리에서는 정렬 방법을 선택하는 전략 패턴을 사용할 수 있습니다. - 게임의 행동: 게임 캐릭터의 움직임이나 공격 패턴을 전략 패턴을 사용해 상황에 맞게 변경할 수 있습니다.
- UI에서의 사용자 이벤트 처리: 다양한 방식으로 사용자 이벤트(클릭, 드래그 등)를 처리할 때, 각각의 처리 방식을 전략으로 캡슐화할 수 있습니다.
전략 패턴은 알고리즘이나 행위를 캡슐화하여 클라이언트가 필요에 따라 동적으로 행위를 교체할 수 있게 함으로써, 코드의 유연성과 확장성을 높이는 데 매우 유용한 패턴입니다.
반응형
'언어 > Java' 카테고리의 다른 글
[ Java ] Template Method Pattern - 템플릿 메서드 패턴 알아보기 (1) | 2024.10.03 |
---|---|
[ Java ] Observer Pattern - 옵저버 패턴 알아보기 (3) | 2024.10.03 |
[ Java ] Proxy Pattern - 프록시 패턴 알아보기 (1) | 2024.10.03 |
[ Java ] Decoration Pattern - 데코레이션 패턴 알아보기 (0) | 2024.10.03 |
[ Java ] Builder Pattern - 빌더 패턴 알아보기 (1) | 2024.10.03 |