Strategy는 전략이며, 소프트웨어에서의 전략은 특정 기능을 어떤식으로 구현할지에 대한 알고리즘 혹은 비즈니스 로직이다.
Strategy 패턴은 하나의 목적을 가지는 여러개의 전략이 있을 때 이를 효과적으로 관리하고 또 교체하여 사용하기 편리하게 하기 위해 사용한다. 각 전략들 간에 공통된 인터페이스를 두고, 구체적인 구현체만 추가 혹은 수정하여 사용한다.
Strategy 패턴은 굉장히 다양하게 쓰일 수 있다. 그중 대표적으로는 결제 시스템에서 결제 수단을 관리할 때, 혹은 게임에서 몬스터의 상태에 따라 행동패턴을 변화시킬 때 사용할 수 있다.
Strategy 패턴의 구조는 비교적 단순하다.
Strategy 전략
전략을 이용하는 인터페이스를 정의
ConcreteStrategy 구체적인 전략
Strategy에서 정의한 인터페이스를 구현하며, 이곳에서 구체적인 로직이나 알고리즘이 작성된다. 즉, Strategy 패턴 자체의 구조는 단순하지만, 구조보다 더 중요한 것은 ConcreteStrategy의 내용이다.
Context 문맥
Strategy의 인터페이스를 호출하며 필요에 따라 다양한 ConcreteStrategy를 가지고 있는다.
Strategy 패턴은 결제시스템을 상상하며 구조만 간단하게 구현해보기로 한다.
우선 결제를 요청하는 메소드 pay
가 정의된 전략 인터페이스를 먼저 만든다.
interface PaymentStrategy {
pay(amount: number): void;
}
이제 구현체를 앞서 정의한 인터페이스를 필요한 종류만큼 작성한다. 여기서는 결제 방법이 신용카드와 페이팔 두 가지 방법이 있다고 가정하자.
class CreditCardPayment implements PaymentStrategy {
pay(amount: number): void {
console.log(`Paying ${amount} using Credit Card`);
}
}
class PayPalPayment implements PaymentStrategy {
pay(amount: number): void {
console.log(`Paying ${amount} using PayPal`);
}
}
마지막으로 전략을 관리하고 사용하는 객체를 만든다.
class PaymentContext {
constructor(
private paymentStrategy: PaymentStrategy,
) {}
pay(amount: number) {
this.paymentStrategy.pay(amount);
}
set(strategy: PaymentStrategy) {
this.paymentStrategy = strategy;
}
}
Strategy 패턴의 장점이 유사한 다른 전략으로의 쉬운 교체인만큼 전략을 교체할 수 있는 메소드를 넣는 것이 좋다.
그리고 pay
라는 메소드는 단순히 Strategy에서 정의한 인터페이스만을 불러오고 있는데, 다른 로직이 추가될 수도 있지만 각각의 구현체가 바뀌어도 항상 pay
메소드의 목적을 수행을 보장한다.
const context = new PaymentContext(new CreditCardPayment());
context.pay(100);
context.set(new PayPalPayment());
context.pay(200);
Paying 100 using Credit Card
Paying 200 using PayPal
Java언어로 배우는 디자인 패턴 입문 - 쉽게 배우는 Gof의 23가지 디자인패턴 (영진닷컴)