Skip to content

strategy-pattern

TL;DR

전략 패턴은 알고리즘을 캡슐화하고, 이를 상호 교환 가능하도록 하여 클라이언트와 독립적으로 알고리즘을 변경할 수 있도록 하는 패턴임.

동기

  • 다양한 알고리즘을 하드코딩하는 것은 유지보수에 비효율적임.
  • 알고리즘을 캡슐화함으로써 코드 크기 증가와 유지보수 비용을 줄일 수 있음.
  • 필요에 따라 알고리즘을 쉽게 교체할 수 있음.
  • 알고리즘을 캡슐화한 클래스를 정의해 문제를 해결했음.

활용성

  • 개념적으로 관련된 여러 클래스가 조금씩 다른 행동을 할 때 사용함.
  • 알고리즘을 자주 변형해야 할 때 유용함.
  • 복잡한 자료 구조를 노출하지 않고 사용해야 할 때 적합함.
  • 많은 조건문을 사용하는 클래스 대신, 전략 클래스를 정의하는 것이 더 나음.

구조

  • Context는 ConcreteStrategy로 구성된 후, Strategy 참조자를 관리함.
  • Strategy는 알고리즘의 인터페이스로 정의됨.
  • ConcreteStrategy는 Strategy 인터페이스를 구현함.

결과

  • 장점
    • 동일 계열의 알고리즘을 생성할 수 있음.
    • 서브클래싱을 사용하지 않아도 됨.
    • 조건문을 제거할 수 있음.
    • 다양한 구현 선택이 가능해짐.
  • 비용
    • 사용자가 서로 다른 전략을 이해해야 함.
    • Strategy 객체와 Context 객체 사이의 오버헤드가 발생함.
    • 객체 수가 증가함.

구현

  1. Strategy와 Context의 인터페이스를 정의함.
  2. 전략을 템플릿 매개변수로 사용할 수 있음.
  3. 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)