strategy-pattern
TL;DR⚑
전략 패턴은 알고리즘을 캡슐화하고, 이를 상호 교환 가능하도록 하여 클라이언트와 독립적으로 알고리즘을 변경할 수 있도록 하는 패턴임.
동기⚑
- 다양한 알고리즘을 하드코딩하는 것은 유지보수에 비효율적임.
- 알고리즘을 캡슐화함으로써 코드 크기 증가와 유지보수 비용을 줄일 수 있음.
- 필요에 따라 알고리즘을 쉽게 교체할 수 있음.
- 알고리즘을 캡슐화한 클래스를 정의해 문제를 해결했음.
활용성⚑
- 개념적으로 관련된 여러 클래스가 조금씩 다른 행동을 할 때 사용함.
- 알고리즘을 자주 변형해야 할 때 유용함.
- 복잡한 자료 구조를 노출하지 않고 사용해야 할 때 적합함.
- 많은 조건문을 사용하는 클래스 대신, 전략 클래스를 정의하는 것이 더 나음.
구조⚑
- Context는 ConcreteStrategy로 구성된 후, Strategy 참조자를 관리함.
- Strategy는 알고리즘의 인터페이스로 정의됨.
- ConcreteStrategy는 Strategy 인터페이스를 구현함.
결과⚑
- 장점
- 동일 계열의 알고리즘을 생성할 수 있음.
- 서브클래싱을 사용하지 않아도 됨.
- 조건문을 제거할 수 있음.
- 다양한 구현 선택이 가능해짐.
- 비용
- 사용자가 서로 다른 전략을 이해해야 함.
- Strategy 객체와 Context 객체 사이의 오버헤드가 발생함.
- 객체 수가 증가함.
구현⚑
- Strategy와 Context의 인터페이스를 정의함.
- 전략을 템플릿 매개변수로 사용할 수 있음.
- Strategy 객체에 선택성을 부여할 수 있음.
from abc import ABC, abstractmethod
# Strategy 인터페이스
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount):
pass
# ConcreteStrategy 구현 - 신용카드 결제
class CreditCardPayment(PaymentStrategy):
def __init__(self, name, card_number, cvv, expiry_date):
self.name = name
self.card_number = card_number
self.cvv = cvv
self.expiry_date = expiry_date
def pay(self, amount):
print(f"{amount}원 결제 완료 - 신용카드: {self.card_number} 사용")
# ConcreteStrategy 구현 - 페이팔 결제
class PayPalPayment(PaymentStrategy):
def __init__(self, email):
self.email = email
def pay(self, amount):
print(f"{amount}원 결제 완료 - PayPal 계정: {self.email} 사용")
# ConcreteStrategy 구현 - 비트코인 결제
class BitcoinPayment(PaymentStrategy):
def __init__(self, wallet_address):
self.wallet_address = wallet_address
def pay(self, amount):
print(f"{amount}원 결제 완료 - Bitcoin 지갑: {self.wallet_address} 사용")
# Context 클래스
class Order:
def __init__(self, amount):
self.amount = amount
def process_order(self, payment_strategy: PaymentStrategy):
payment_strategy.pay(self.amount)
# 사용 예시
if __name__ == "__main__":
order = Order(10000) # 10,000원 결제
# 신용카드 결제 전략 선택
credit_card = CreditCardPayment("홍길동", "1234-5678-9876-5432", "123", "12/25")
order.process_order(credit_card)
# PayPal 결제 전략 선택
paypal = PayPalPayment("user@example.com")
order.process_order(paypal)
# Bitcoin 결제 전략 선택
bitcoin = BitcoinPayment("1A2B3C4D5E6F7G8H9I0J")
order.process_order(bitcoin)