| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
- Laravel
- MySQL
- mcp server
- 객체복제
- 디자인패턴
- mcp client
- ai 에이전트
- SQL
- 어댑터패턴
- ai agent
- SQL문법
- 데코레이터패턴
- PHP객체지향
- 매직메서드
- LLM
- Agent Loop
- 객체지향
- linux 권한
- OOP
- PHP
- 데이터베이스
- SQL기초
- Tool Calling
- MCP
- dhgrp
- 인덱스
- 라라벨
- docker
- 소프트웨어설계
- docker network
- Today
- Total
개발블로그
[디자인 패턴] 전략패턴 본문
개념
필요성
프로그램을 만들다 보면 같은 흐름 안에서 일부 동작만 달라지는 경우가 있음.
의미
실행할 알고리즘이나 정책을 별도의 객체로 분리하고, 실행 시점에 필요한 전략을 선택해서 사용하는 패턴
ex) 할인 예시에서의 전략
정액할인 - 일정 금액을 할인하는 방식
정률 할인 - 주문 금액의 일정 비율을 할인하는 방식
VIP 할인 - 회원 등급에 따라 더 높은 비율을 할인하는 방식
쿠폰 할인 - 쿠폰 조건에 따라 할인 금액을 계산하는 방식
핵심 구조
| 구성 요소 | 역할 | 예시 |
| Context | 전략을 사용하는 객체 | 주문 가격 계산기 |
| Strategy | 공통으로 따라야 할 전략의 형태 | 할인 정책 |
| Concrete Strategy | 실제 동작을 구현한 구체적인 전략 | 정액 할인, 정률 할인, VIP 할인 |
예시
ex) 주문금액에 할인을 적용
전체흐름 : 주문 금액을 계산하고, 할인 금액을 반영하고, 최종 금액을 반환한다
하지만, 할인 방식은 상황에 따라 달라질 수 있음
| 할인 방식 | 설명 |
| 정액 할인 | 일정 금액을 할인한다. |
| 정률 할인 | 주문 금액의 일정 비율을 할인한다. |
| 등급 할인 | 회원 등급에 따라 할인율이 달라진다. |
| 쿠폰 할인 | 쿠폰 조건에 따라 할인 금액이 달라진다. |
처음에는 조건문으로 할인 방식을 처리할 수 있음
def calculate_price(price, discount_type):
if discount_type == "fixed":
return price - 1000
elif discount_type == "rate":
return price * 0.9
elif discount_type == "vip":
return price * 0.8
return price
할인 방식이 적고 변경 가능성이 낮다면 충분히 단순한 해결 방법이 될 수 있지만,
할인 방식이 계속 추가되거나 각 할인 정책의 계산 규칙이 복잡해지면 문제가 생김
ex)
| 문제 | 설명 |
| 수정 범위 증가 | 할인 정책이 추가될 때마다 기존 함수를 수정해야 한다. |
| 책임 혼합 | 가격 계산 흐름과 할인 정책별 계산 로직이 한곳에 섞인다. |
| 테스트 어려움 | 각 할인 정책을 독립적으로 테스트하기 어렵다. |
| 실수 가능성 증가 | 조건문을 추가하면서 기존 조건 순서나 기본값을 잘못 건드릴 수 있다. |
=> 바뀔 가능성이 높은 할인 정책이 하나의 함수 안에 계속 쌓이게 됨
예를들어 이벤트 할인 정책만 수정하고 싶어도 calculate_price()전체를 열어야 한다
이 함수 안에는 다른 할인 정책도 함께 들어 있기 때문에, 의도하지 않게 기존 로직을 건드릴 가능성이 생김
또한 할인 정책별 규칙이 복잡해지면 함수의 역할도 흐려진다.
(가격 계산 함수인지? 할인 정책을 선택하는 함수인지?)
이런 상황에서는 바뀌는 부분을 분리할 필요가 있음.
이런 할인 정책들을 별도의 객체로 분리하기
먼저 모든 할인 정책이 공통으로 따라야 할 형태를 정함
class DiscountStrategy:
def discount(self, price):
pass
=> 구체적으로 할인 계산을 직접 하지 않는다.
대신 할인 정책이라면 discount()라는 동작을 제공해야 한다는 기준을 만든다.
이제 각 할인 방식을 별도의 클래스로 구현
# 정액 할인 계산
class FixedDiscount(DiscountStrategy):
def discount(self, price):
return price - 1000
# 정률 할인 계산
class RateDiscount(DiscountStrategy):
def discount(self, price):
return price * 0.9
# VIP 할인 계산
class VipDiscount(DiscountStrategy):
def discount(self, price):
return price * 0.8
=> 각 클래스는 자신이 맡은 할인 방식만 책임 짐
이제 가격 계산 흐름은 구체적인 할인 방식에 직접 의존하지 않고, 할인 전략을 받아서 사용
class PriceCalculator:
def __init__(self, discount_strategy):
self.discount_strategy = discount_strategy
def calculate(self, price):
return self.discount_strategy.discount(price)
PriceCalculator는 어떤 할인 정책이 들어오는지 알 필요가 없음.
그저 전달받은 전략 객체의 discount()를 호출함
calculator = PriceCalculator(FixedDiscount())
print(calculator.calculate(10000)) # 9000
calculator = PriceCalculator(RateDiscount())
print(calculator.calculate(10000)) # 9000
calculator = PriceCalculator(VipDiscount())
print(calculator.calculate(10000)) # 8000
| 구분 | 역할 |
| PriceCalculator | 가격 계산 흐름을 담당 |
| DiscountStrategy | 할인 정책의 공통 형태를 정의 |
| FixedDiscount, RateDiscount, VipDiscount | 실제 할인 계산을 담당 |
새로운 할인 정책이 추가되어도 기존 PriceCalculator를 수정하지 않아도 됨
=> 쿠폰 할인을 사용하고 싶다면 새로운 전략 객체를 전달하면 됨
class CouponDiscount(DiscountStrategy):
def discount(self, price):
return price - 3000
장점
장점
| 장점 | 설명 |
| 분기 로직 감소 | 여러 동작을 하나의 조건문에 계속 추가하지 않아도 된다 |
| 책임 분리 | 공통 흐름과 세부 동작을 분리할 수 있다 |
| 확장 용이 | 새로운 동작을 기존 코드 수정 대신 새로운 전략으로 추가할 수 있다 |
| 교체 용이 | 실행 시점에 필요한 전략을 바꿔 사용할 수 있다 |
| 테스트 용이 | 각 전략을 독립적으로 테스트할 수 있다. |
효과적인 상황
| 상황 | 이유 |
| 같은 목적을 가진 여러 동작이 있는 경우 | 동작별로 전략 객체를 나눌 수 있다. |
| 세부 동작이 자주 추가되거나 변경되는 경우 | 기존 흐름을 덜 수정하고 확장할 수 있다. |
| 실행 시점에 동작을 선택해야 하는 경우 | 필요한 전략을 외부에서 전달해 사용할 수 있다. |
| 동작별 테스트가 필요한 경우 | 전략 단위로 테스트하기 쉽다. |
주의점
조건문이 있다는 이유만으로 무조건 전략 패턴을 적용하면 오히려 구조가 복잡해질 수 있음
| 질문 | 의미 |
| 바뀌는 동작이 명확한가? | 무엇을 전략으로 분리할지 확인한다. |
| 전략이 여러 개이거나 늘어날 가능성이 있는가? | 패턴 적용의 이점이 있는지 판단한다. |
| 전략별 로직이 독립적으로 관리될 만큼 복잡한가? | 클래스 분리 비용보다 얻는 이점이 큰지 본다. |
| 전략 선택 책임은 어디에 둘 것인가? | 전략 생성과 선택 로직이 흩어지지 않게 한다. |
| 조건문이 더 단순하지 않은가? | 과한 설계를 피한다. |
'STUDY > CS' 카테고리의 다른 글
| [디자인패턴] 옵저버 패턴 (0) | 2026.09.04 |
|---|---|
| [디자인패턴] 팩토리 패턴 (1) | 2026.09.04 |
| [디자인 패턴] 디자인 패턴이란? 반복되는 설계 문제를 해결하는 방법 (0) | 2026.09.03 |
| [객체지향] SOLID 원칙 : 좋은 객체지향 설계를 판단하는 5가지 기준 (0) | 2026.09.03 |
| [객체지향] 클래스를 쓰면 객체지향일까? 객체지향이 필요한 진짜 이유 (0) | 2026.09.03 |