
소프트웨어 디자인 패턴의 고전으로 불리는 전략 패턴(Strategy Pattern)은 특정 알고리즘을 캡슐화하여 런타임에 교체할 수 있게 만드는 강력한 도구입니다. 하지만 Java나 C++ 같은 정적 타입 언어에서 익힌 '인터페이스-구현체' 방식의 엄격한 클래스 구조를 파이썬에 그대로 대입하는 것은 파이썬이 가진 잠재력을 절반만 사용하는 것과 같습니다. 파이썬에서 함수는 '일급 객체(First-class Object)'입니다. 즉, 함수를 변수에 할당하고, 인자로 전달하며, 반환값으로 사용할 수 있습니다. 이 특성을 활용하면 복잡한 추상 베이스 클래스(ABC) 없이도 훨씬 간결하고 유지보수가 쉬운 전략 패턴을 완성할 수 있습니다. 본 가이드에서는 실무 개발자가 즉시 활용할 수 있는 테크닉과 7가지 구체적인 해결 사례를 제시합니다.
1. 클래스 기반 전략 vs 파이썬 함수형 전략의 핵심 차이
전통적인 방식은 알고리즘마다 클래스를 정의해야 하므로 코드 비대화(Boilerplate)가 발생합니다. 반면 파이썬의 일급 객체 특성을 활용하면 함수 그 자체를 전략으로 취급하여 구조를 단순화할 수 있습니다.
| 비교 항목 | 전통적 클래스 전략 패턴 | 파이썬 함수형 전략 패턴 |
|---|---|---|
| 구현 방식 | 인터페이스 상속 및 메서드 오버라이딩 | 함수 참조 또는 Callable 객체 전달 |
| 코드 길이 | 비교적 길고 구조적임 | 매우 짧고 직관적임 |
| 유연성 | 정해진 인터페이스 구조를 따라야 함 | 람다(Lambda) 등 익명 함수 결합 가능 |
| 상태 저장 | 인스턴스 속성(self)에 저장 | 클로저(Closure)를 통해 캡슐화 |
| 결합도 | 상위 타입에 대한 의존성 존재 | 덕 타이핑(Duck Typing) 기반 낮은 결합도 |
2. 실무 해결을 위한 7가지 Sample Examples
이 섹션에서는 다양한 비즈니스 로직 상황에서 함수형 전략 패턴을 적용하여 문제를 해결하는 구체적인 사례를 소개합니다.
Example 1: 동적 할인 정책 시스템 (기본 함수 참조)
가장 기본적인 형태로, 결제 모듈에서 할인 알고리즘을 함수 객체로 갈아끼우는 방식입니다.
def bulk_discount(order):
return order.total() * 0.1 if order.items >= 10 else 0
def loyalty_discount(order):
return order.total() * 0.05
class Order:
def __init__(self, price, items, strategy=None):
self.price = price
self.items = items
self.strategy = strategy
def total(self):
return self.price * self.items
def due(self):
discount = self.strategy(self) if self.strategy else 0
return self.total() - discount
# 사용 예시
order = Order(100, 12, strategy=bulk_discount)
print(f"결제 금액: {order.due()}")
Example 2: 데이터 직렬화 엔진 (Serializer Strategy)
데이터를 JSON, XML, YAML 등 다양한 포맷으로 출력할 때 유용합니다.
import json
def to_json(data):
return json.dumps(data)
def to_plain_text(data):
return ", ".join(f"{k}:{v}" for k, v in data.items())
def export_data(data, format_func):
return format_func(data)
raw_info = {"name": "Gemini", "role": "Assistant"}
print(export_data(raw_info, to_json))
Example 3: 파일 압축 매니저 (Closure 활용)
특정 옵션이 포함된 전략을 런타임에 생성하여 전달하는 클로저 패턴입니다.
def make_compression_strategy(level):
def compress(data):
return f"Compressing {data} with level {level}"
return compress
fast_compress = make_compression_strategy(level=1)
deep_compress = make_compression_strategy(level=9)
print(fast_compress("MyData"))
Example 4: 유효성 검사 파이프라인 (Lambda 결합)
간단한 로직은 람다를 사용하여 클래스 선언 없이 즉석에서 전략을 수립합니다.
def validate_user(user, constraint):
return constraint(user)
user_data = {"age": 25, "premium": True}
# 18세 이상이며 프리미엄 회원인지 검사하는 전략
is_eligible = validate_user(user_data, lambda u: u['age'] > 18 and u['premium'])
print(f"승인 여부: {is_eligible}")
Example 5: 로그 기록 대상 제어 (Callable 객체)
함수뿐만 아니라 __call__ 메서드가 구현된 인스턴스를 전략으로 활용합니다.
class DatabaseLogger:
def __init__(self, db_url):
self.url = db_url
def __call__(self, message):
print(f"Log to {self.url}: {message}")
def console_logger(message):
print(f"Console: {message}")
def log_event(msg, strategy):
strategy(msg)
db_log = DatabaseLogger("mysql://localhost:3306")
log_event("System Start", db_log)
Example 6: 정렬 기준의 동적 변경 (Higher-order Function)
파이썬의 내장 sorted 함수는 전략 패턴이 함수형으로 녹아든 완벽한 사례입니다.
products = [('apple', 2500), ('banana', 1500), ('cherry', 4000)]
# 가격 순으로 정렬하는 전략 제공
by_price = sorted(products, key=lambda x: x[1])
# 이름 길이 순으로 정렬하는 전략 제공
by_name_len = sorted(products, key=lambda x: len(x[0]))
Example 7: 비즈니스 규칙 엔진 (Registry Pattern 연동)
딕셔너리에 함수를 등록하여 조건에 맞는 전략을 자동으로 선택하게 합니다.
def route_air(package): return f"Flying {package}"
def route_sea(package): return f"Shipping {package}"
shipping_methods = {
'express': route_air,
'standard': route_sea
}
def ship(package, priority):
strategy = shipping_methods.get(priority, route_sea)
return strategy(package)
print(ship("Smartphone", "express"))
3. 결론: 왜 함수형 전략을 선택해야 하는가?
파이썬의 철학은 "단순한 것이 복잡한 것보다 낫다(Simple is better than complex)"입니다. 수많은 클래스 파일을 생성하고 상속 관계를 추적하는 대신, 일급 객체로서의 함수를 활용하면 다음과 같은 이득을 얻을 수 있습니다.
- 가독성: 로직이 분산되지 않고 호출부 근처에서 확인 가능합니다.
- 성능: 클래스 인스턴스화 오버헤드가 줄어듭니다.
- 테스트: 함수는 독립적이므로 모킹(Mocking)과 유닛 테스트가 매우 간단해집니다.
4. 내용의 출처 및 참고 자료
본 포스팅의 전문 지식은 다음의 자료들을 바탕으로 재구성되었습니다.
- Fluent Python (2nd Edition) by Luciano Ramalho - "Function as First-Class Objects"
- Design Patterns: Elements of Reusable Object-Oriented Software by GoF
- Python Official Documentation:
functoolsandabcmodules - Refactoring.Guru - "Strategy Pattern Implementation in Python"
'Artificial Intelligence > 60. Python' 카테고리의 다른 글
| [PYTHON] 명령 패턴(Command Pattern)을 함수 객체로 단순화하는 3가지 방법과 7가지 실무 예제 (0) | 2026.04.01 |
|---|---|
| [PYTHON] pytest.fixture scope 설정을 최적화하는 5가지 방법과 성능 차이 해결 사례 (0) | 2026.04.01 |
| [PYTHON] 왜 AI 개발에 Python이 가장 많이 쓰이나요? 5가지 이유와 타 언어와의 결정적 차이 해결 사례 (0) | 2026.04.01 |
| [PYTHON] Anaconda와 일반 Python의 5가지 결정적 차이 및 환경 충돌 해결 방법 (0) | 2026.04.01 |
| [PYTHON] 가상환경(venv, conda)을 왜 3가지 이유로 꼭 써야 하나요? 충돌 해결 방법 7가지 (0) | 2026.04.01 |