JavaScript에서 전략 패턴(Strategy Pattern)은 알고리즘의 집합을 정의하는 인터페이스와 그 인터페이스를 구현하는 클래스로 구성됩니다. 클래스는 인터페이스를 상속받아 구현합니다. 이 알고리즘은 런타임에 쉽게 변경할 수 있습니다.
전략 패턴은 알고리즘을 구조적으로 분리하여 각각의 알고리즘을 독립적으로 변경할 수 있도록 하는 디자인 패턴입니다.
이 패턴을 사용하면 각각의 알고리즘을 쉽게 교체할 수 있어 개발 및 유지보수의 효율성이 높아집니다.
전략 패턴은 프로그램의 구조를 변경하지 않으면서 알고리즘을 변경할 수 있는 기능을 제공합니다.
이 패턴을 사용하면 높은 유연성을 가진 알고리즘을 쉽게 구현할 수 있습니다.
- 알고리즘의 집합을 정의하는 인터페이스??
"알고리즘"이란, 특정 문제를 해결하기 위한 계산 과정을 의미합니다. 예를 들어, 정렬 알고리즘은 데이터를 정렬하는 과정을 말합니다.
코드에서 "알고리즘을 정의하는 인터페이스"는 객체의 행동을 정의하는 것을 의미합니다.
예를 들어, FlyBehavior 인터페이스는 객체가 어떻게 날아야 할지 정의하고, QuackBehavior 인터페이스는 객체가 어떻게 꽥꽥이는 소리를 내야 할지 정의합니다.
JS 코드로 확인해 보는 전략패턴 예제 1) 쇼핑 카트 클래스에서 결제 전략을 적용하는 예제
// 알고리즘을 정의하는 인터페이스 : 어떤 방식으로 결제를 하는가? 알고리즘
const PaymentStrategy = {
pay(amount) {
throw new Error("This method must be overwritten!");
},
};
// PaymentStrategy 인터페이스를 상속받은 클래스
class CreditCardPayment extends PaymentStrategy {
pay(amount) {
console.log(`Paying ${amount} using Credit Card`);
}
}
class PayPalPayment extends PaymentStrategy {
pay(amount) {
console.log(`Paying ${amount} using PayPal`);
}
}
// PaymentStrategy 객체를 저장하는 클래스
class ShoppingCart {
constructor(paymentStrategy) {
this.items = [];
this.paymentStrategy = paymentStrategy;
}
addItem(item) {
this.items.push(item);
}
getTotal() {
return this.items.reduce((acc, item) => acc + item.price, 0);
}
pay() {
const amount = this.getTotal();
this.paymentStrategy.pay(amount);
}
}
const shoppingCart = new ShoppingCart(new CreditCardPayment());
shoppingCart.addItem({ name: "item1", price: 100 });
shoppingCart.addItem({ name: "item2", price: 200 });
shoppingCart.pay(); // "Paying 300 using Credit Card"
const shoppingCart2 = new ShoppingCart(new PayPalPayment());
shoppingCart2.addItem({ name: "item1", price: 100 });
shoppingCart2.addItem({ name: "item2", price: 200 });
shoppingCart2.pay(); // "Paying 300 using PayPal"
PaymentStrategy 인터페이스는 결제 방식을 정의하며, CreditCardPayment 클래스와 PayPalPayment 클래스는 각각 신용카드로 결제하는 클래스와 페이팔로 결제하는 클래스입니다.
ShoppingCart 클래스는 생성자에서 PaymentStrategy 객체를 전달받습니다. 결제를 수행할 때, pay 메서드는 현재 PaymentStrategy 객체의 pay 메서드를 호출하여 결제를 수행합니다.
TS 코드로 확인해 보는 전략패턴 예제 1) 쇼핑 카트 클래스에서 결제 전략을 적용하는 예제
// 알고리즘을 정의하는 인터페이스
interface PaymentStrategy {
pay(amount: number): void;
}
// PaymentStrategy 인터페이스를 상속받은 클래스
class CreditCardPayment implements PaymentStrategy {
pay(amount: number) {
console.log(`Paying ${amount} using Credit Card`);
}
}
class PayPalPayment implements PaymentStrategy {
pay(amount: number) {
console.log(`Paying ${amount} using PayPal`);
}
}
// PaymentStrategy 객체를 저장하는 클래스
class ShoppingCart {
items: { name: string; price: number }[] = [];
paymentStrategy: PaymentStrategy;
constructor(paymentStrategy: PaymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
addItem(item: { name: string; price: number }) {
this.items.push(item);
}
getTotal() {
return this.items.reduce((acc, item) => acc + item.price, 0);
}
pay() {
const amount = this.getTotal();
this.paymentStrategy.pay(amount);
}
}
const shoppingCart = new ShoppingCart(new CreditCardPayment());
shoppingCart.addItem({ name: "item1", price: 100 });
shoppingCart.addItem({ name: "item2", price: 200 });
shoppingCart.pay(); // "Paying 300 using Credit Card"
const shoppingCart2 = new ShoppingCart(new PayPalPayment());
shoppingCart2.addItem({ name: "item1", price: 100 });
shoppingCart2.addItem({ name: "item2", price: 200 });
shoppingCart2.pay(); // "Paying 300 using PayPal"
JS 코드로 확인해 보는 전략패턴 예제 2) 게임에서 적군의 공격 전략을 나타내는 것
// 알고리즘을 정의하는 인터페이스
const AttackStrategy = {
attack() {
throw new Error("This method must be overwritten!");
},
};
// AttackStrategy 인터페이스를 상속받은 클래스
class PhysicalAttack extends AttackStrategy {
attack() {
console.log("Physical attack!");
}
}
class MagicalAttack extends AttackStrategy {
attack() {
console.log("Magical attack!");
}
}
// AttackStrategy 객체를 저장하는 클래스
class Enemy {
constructor(attackStrategy) {
this.attackStrategy = attackStrategy;
}
attack() {
this.attackStrategy.attack();
}
}
const enemy1 = new Enemy(new PhysicalAttack());
enemy1.attack(); // "Physical attack!"
const enemy2 = new Enemy(new MagicalAttack());
enemy2.attack(); // "Magical attack!"
TS 코드로 확인해 보는 전략패턴 예제 2) 게임에서 적군의 공격 전략을 나타내는 것
interface AttackStrategy {
attack(): void;
}
class PhysicalAttack implements AttackStrategy {
attack(): void {
console.log("Physical attack!");
}
}
class MagicalAttack implements AttackStrategy {
attack(): void {
console.log("Magical attack!");
}
}
class Enemy {
private attackStrategy: AttackStrategy;
constructor(attackStrategy: AttackStrategy) {
this.attackStrategy = attackStrategy;
}
attack(): void {
this.attackStrategy.attack();
}
}
const enemy1 = new Enemy(new PhysicalAttack());
enemy1.attack(); // "Physical attack!"
const enemy2 = new Enemy(new MagicalAttack());
enemy2.attack(); // "Magical attack!"
TS 코드로 확인해 보는 전략패턴 예제 3) 배송비를 계산하는 로직
interface ShippingStrategy {
calculate(order: Order): number;
}
class StandardShipping implements ShippingStrategy {
calculate(order: Order): number {
return 5 + 2 * order.itemCount;
}
}
class ExpressShipping implements ShippingStrategy {
calculate(order: Order): number {
return 10 + 3 * order.itemCount;
}
}
class Order {
itemCount: number;
shippingStrategy: ShippingStrategy;
constructor(itemCount: number, shippingStrategy: ShippingStrategy) {
this.itemCount = itemCount;
this.shippingStrategy = shippingStrategy;
}
total(): number {
return this.itemCount * 20 + this.shippingStrategy.calculate(this);
}
}
const order1 = new Order(5, new StandardShipping());
console.log(`Order 1 total: ${order1.total()}`); // Order 1 total: 115
const order2 = new Order(5, new ExpressShipping());
console.log(`Order 2 total: ${order2.total()}`); // Order 2 total: 125
전략 패턴을 실무에서 어떤 곳에 적용하면 좋을까?
전략 패턴은 같은 문제를 해결하는 여러 알고리즘이 존재할 때, 이를 캡슐화하여 서로 교환 가능한 객체들로 만들어서 알고리즘을 선택하거나 바꿀 수 있는 프로그래밍 패턴이다.
알고리즘을 정의하는 인터페이스와 인터페이스를 상속받은 클래스, 알고리즘 객체를 저장하는 클래스로 구성된다. 이 패턴은 알고리즘을 쉽게 교체할 수 있도록 하고, 알고리즘을 재사용할 수 있는 장점이 있다.
실무에서 적용하기 좋은 곳으로는 알고리즘이 동적으로 변경되는 경우, 다양한 알고리즘을 적용하여 테스트하는 경우, 알고리즘의 재사용성이 필요한 경우 등이 있다.
예를 들어, 쇼핑 카트 애플리케이션에서 결제 전략을 변경할 때, 결제 전략을 변경하면서 결제 과정에 대한 영향을 최소화 할 수 있다. 또한 게임에서 적의 공격 방식을 변경할 때, 공격 방식을 변경하면서 공격 과정에 대한 영향을 최소화 할 수 있다. 이처럼, 알고리즘을 쉽게 교체할 수 있는 프로그램에서 Strategy pattern을 사용하면 유용할 수 있다.
'Frontend > JavaScript & Jquery' 카테고리의 다른 글
이벤트 버블링과 캡쳐링 이해하기 (1) | 2023.11.25 |
---|---|
[JS, Jquery] 요소의 속성, 프로퍼티 값 (0) | 2023.03.07 |
[JS, Jquery] 체크박스 script (0) | 2023.02.28 |
Element.insertAdjacentHTML() (0) | 2022.12.25 |
null과 undefined (0) | 2022.12.07 |