본문 바로가기
BE 공부/클린 코드

[디자인 패턴 입문] Strategy(전략 패턴)

by 꼬질꼬질두부 2025. 7. 3.
반응형

1. 개념 정리

전략 패턴(Strategy Pattern)은 실행할 수 있는 여러 알고리즘(전략) 중 하나를 상황에 따라 선택해서 사용할 수 있도록 만드는 디자인 패턴입니다.

쉽게 말해 “상황에 따라 다른 방식으로 처리하고 싶을 때, 그 방법들을 미리 정의해놓고 필요한 것만 골라 쓰는 구조”라고 보면 됩니다.

예를 들어 쇼핑몰에서 가격을 계산하는 방식이 여러 개 있다고 가정해봅시다.

  • 일반 계산 방식
  • 할인 쿠폰을 적용한 계산
  • 멤버십 등급에 따라 포인트를 반영한 계산

이럴 때 전략 패턴을 사용하면 계산 로직들을 미리 전략으로 분리하고,
사용할 때마다 원하는 전략을 선택해서 주입할 수 있게 됩니다.

자바스크립트에서는 함수도 값처럼 다룰 수 있기 때문에, 전략을 함수로 정의해서 객체나 클래스에 전달하면 쉽게 구현할 수 있습니다!


2. 예제 코드

1) 전략을 함수로 분리한 기본 구조

// 전략 함수들 정의
function normalPricing(price) {
  return price;
}

function discountPricing(price) {
  return price * 0.9; // 10% 할인
}

function vipPricing(price) {
  return price * 0.8; // 20% 할인
}

// 전략을 주입받는 컨텍스트
function calculatePrice(price, strategy) {
  return strategy(price);
}

// 사용 예
console.log(calculatePrice(10000, normalPricing)); // 10000
console.log(calculatePrice(10000, discountPricing)); // 9000
console.log(calculatePrice(10000, vipPricing)); // 8000

가격 계산 방식은 3가지로 나뉘고, 각각 별도의 함수로 정의됩니다.

calculatePrice()는 실제로 가격을 계산하는 함수인데, 어떤 방식으로 계산할지는 외부에서 결정합니다.

이 구조 덕분에 계산 전략을 쉽게 교체하거나 테스트할 수 있고, 로직이 변경돼도 calculatePrice()는 건드릴 필요가 없습니다.


3. 언제 사용하면 좋을까?

1) 다양한 조건에 따라 처리 로직이 바뀌는 경우

예시 상황:
로그인한 사용자의 등급에 따라 결제 할인률이 다르게 적용되는 쇼핑몰

예시 코드:

const pricingStrategies = {
  normal: price => price,
  silver: price => price * 0.95,
  gold: price => price * 0.9
};

function calculate(price, level) {
  const strategy = pricingStrategies[level] || pricingStrategies['normal'];
  return strategy(price);
}

고객 등급이 늘어나더라도 전략만 추가하면 되고, 가격 계산 함수는 바뀌지 않으니 유지보수가 매우 쉬워집니다.


2) 조건문이 많아지는 걸 피하고 싶을 때

예시 상황:
결제 수단(PayPal, 카드, 포인트 등)에 따라 다른 결제 로직을 적용해야 할 때

예시 코드:

const payStrategies = {
  card: amount => `카드로 ${amount}원 결제 완료`,
  paypal: amount => `PayPal로 ${amount}원 결제 완료`,
  point: amount => `포인트로 ${amount}원 결제 완료`
};

function processPayment(amount, method) {
  const pay = payStrategies[method];
  if (!pay) throw new Error("지원하지 않는 결제 수단입니다.");
  return pay(amount);
}

console.log(processPayment(10000, 'card')); // 카드로 10000원 결제 완료

결제 수단이 추가되어도 새로운 전략만 추가하면 됩니다. if-else나 switch 문 없이도 깨끗하고 직관적인 코드를 유지할 수 있습니다.


4. 주의사항 (문제와 해결 방법)

1) 전략의 갯수가 너무 많아질 수 있음

  • 전략이 많아지면 어떤 전략이 어디에 쓰이는지 추적이 어려워질 수 있습니다.

예시 상황:
결제 방식이 계속 늘어나는 쇼핑몰에서 어떤 전략이 어디서 사용되는지 추적하기 어려움.

개선 코드 예시:

// 각 전략을 별도 모듈로 분리 (예: paymentStrategies/card.js 등)

// strategies/index.js
const card = require('./card');
const paypal = require('./paypal');
const point = require('./point');

module.exports = {
  card,
  paypal,
  point,
};

해결 방법:

  • 전략을 파일 단위로 분리해서 유지보수성을 높이고,
  • 문서화와 주석으로 전략의 역할을 명확히 정리하기

2) 전략이 너무 단순하면 오히려 복잡해질 수 있음

  • 전략이 단순한 경우(예: x * 0.9)라면 오히려 따로 분리하는 게 번거로울 수 있습니다.

예시 상황:

// 너무 단순한 전략의 경우
const strategy = price => price * 0.9; // 너무 간단한 계산

// 불필요하게 함수로 분리하면 오히려 코드량만 증가
function discountStrategy(price) {
  return price * 0.9;
}

해결 방법:

  • 전략 패턴은 조건 분기와 확장성이 많을 때 유리하므로, 전략 개수가 충분하거나 자주 바뀔 때만 적용하기
  • 단순한 연산이라면 굳이 전략 함수로 만들지 않아도 괜찮

정리 요약

  • 전략 패턴은 여러 실행 방식 중 하나를 선택적으로 사용할 수 있게 해줍니다.
  • 조건문 대신 전략 객체를 이용하면 더 깔끔한 코드가 됩니다.
  • 자바스크립트에서는 함수도 값으로 쓸 수 있기 때문에 전략 패턴이 구현하기 쉬운 구조입니다.
  • 단, 전략이 너무 단순하거나 너무 많으면 오히려 복잡해질 수 있으므로 구조와 문서화를 잘 해야 합니다.
반응형

댓글