개발을 하다보면 기능이 추가되며 if/else, switch, 특정 mode등의 옵션 조합이 늘어날 수 있습니다. 이럴 때 적용하면 좋을 디자인 패턴인 Strategy(전략) 패턴에 대해서 알아보도록 하겠습니다.
특정한 규칙을 객체/함수로 분리하고 런타임에 교체 가능하게 만드는 패턴
규칙(무엇을 할지)을 분리해두고 상황에 따라 갈아 끼워 쓰는 구조
분기 감소: if/else,switch가 늘어나는 대신 전략이 늘어나는 구조로 전환
확장에 유리: 새 규칙 추가가 기존 코드 수정이 아니라 전략 추가로 끝남
테스트 용이: 전략 단위로 독립 테스트 가능
책임 분리: 컨텍스트(흐름)와 규칙(알고리즘)이 분리되어 코드가 읽기 쉬움
런타임 교체: 사용자 선택, 환경, 플래그에 따라 동작을 쉽게 바꿀 수 있음
type MemberGrade = 'NORMAL' | 'VIP';
type Coupon = 'NONE' | 'RATE10' | 'FIXED3000';
function calcPrice(price: number, grade: MemberGrade, coupon: Coupon) {
let discounted = price;
// 등급 할인
if (grade === 'VIP') discounted *= 0.9;
// 쿠폰 할인
switch (coupon) {
case 'RATE10':
discounted *= 0.9;
break;
case 'FIXED3000':
discounted -= 3000;
break;
}
return Math.max(0, Math.floor(discounted));
}
규칙이 늘수록 calcPrice가 계속 커지고, VIP + 특정 쿠폰처럼 조합 버그가 생기기 쉬워진다.
// 전략(함수 타입 또는 인터페이스) 정의
type PricingStrategy = (price: number) => number;
// 전략 구현
const noDiscount: PricingStrategy = (p) => p;
const vipDiscount: PricingStrategy = (p) => p * 0.9;
const couponRate10: PricingStrategy = (p) => p * 0.9;
const couponFixed3000: PricingStrategy = (p) => p - 3000;
// 컨텍스트에서 전략 선택/조합
type MemberGrade = 'NORMAL' | 'VIP';
type Coupon = 'NONE' | 'RATE10' | 'FIXED3000';
function compose(...strategies: PricingStrategy[]): PricingStrategy {
return (price) => strategies.reduce((p, s) => s(p), price);
}
// 쿠폰/정책처럼 종류가 늘어나는 값은 Record(Map)로 관리하는 게 확장에 유리
const couponStrategyMap: Record<Coupon, PricingStrategy> = {
NONE: noDiscount,
RATE10: couponRate10,
FIXED3000: couponFixed3000,
};
function getPricingStrategy(grade: MemberGrade, coupon: Coupon): PricingStrategy {
const gradeStrategy = grade === 'VIP' ? vipDiscount : noDiscount;
return compose(gradeStrategy, couponStrategyMap[coupon]);
}
function calcPrice(price: number, grade: MemberGrade, coupon: Coupon) {
const strategy = getPricingStrategy(grade, coupon);
const result = strategy(price);
return Math.max(0, Math.floor(result));
}
여기서 전략을 선택하는 로직까지 switch,if/else로 커지면 다시 분기 코드가 비대해질 수 있습니다.
쿠폰처럼 종류가 늘어나는 값은 Record(Map)으로 관리하면 확장에 더 유리합니다.
Strategy 패턴은 규칙이 늘어나는 지점을 격리시켜 유지보수 비용을 낮추는 방법입니다.