Menu
Coddy logo textTech

전략 패턴

Coddy Python 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 64개 중 48번째.

전략 패턴은 일련의 알고리즘을 정의하고, 각 알고리즘을 캡슐화하며, 이들을 상호 교체 가능하게 만듭니다. 클라이언트 코드를 변경하지 않고도 런타임에 알고리즘을 전환할 수 있습니다.

다음은 다양한 결제 수단을 위한 간단한 전략 클래스들입니다:

class CreditCard:
    def pay(self, amount):
        return f"Paid ${amount} with Credit Card"

class PayPal:
    def pay(self, amount):
        return f"Paid ${amount} with PayPal"

class Bitcoin:
    def pay(self, amount):
        return f"Paid ${amount} with Bitcoin"

각 전략은 동일한 메서드(pay)를 구현하지만, 동작 방식은 서로 다릅니다.

전략을 사용하는 컨텍스트 클래스를 생성합니다:

class ShoppingCart:
    def __init__(self):
        self.total = 0
        self.payment_strategy = None
    
    def add_item(self, price):
        self.total += price
    
    def set_payment_strategy(self, strategy):
        self.payment_strategy = strategy
    
    def checkout(self):
        return self.payment_strategy.pay(self.total)

컨텍스트 클래스는 서로 다른 결제 전략 간에 전환할 수 있습니다.

전략 패턴을 사용하세요:

cart = ShoppingCart()
cart.add_item(50)
cart.add_item(30)

# 신용카드 전략 사용
cart.set_payment_strategy(CreditCard())
print(cart.checkout())

# PayPal 전략으로 전환
cart.set_payment_strategy(PayPal())
print(cart.checkout())

정렬 전략을 사용한 또 다른 예제를 만들어 보겠습니다:

class BubbleSort:
    def sort(self, data):
        return f"Bubble sorted: {sorted(data)}"

class QuickSort:
    def sort(self, data):
        return f"Quick sorted: {sorted(data)}"

class Sorter:
    def __init__(self, strategy):
        self.strategy = strategy
    
    def set_strategy(self, strategy):
        self.strategy = strategy
    
    def sort_data(self, data):
        return self.strategy.sort(data)

# 서로 다른 정렬 전략 사용
numbers = [3, 1, 4, 1, 5]

sorter = Sorter(BubbleSort())
print(sorter.sort_data(numbers))

sorter.set_strategy(QuickSort())
print(sorter.sort_data(numbers))

출력:

Paid $80 with Credit Card
Paid $80 with PayPal
Bubble sorted: [1, 1, 3, 4, 5]
Quick sorted: [1, 1, 3, 4, 5]

핵심 포인트: 전략 패턴(Strategy Pattern)을 사용하면 런타임에 알고리즘을 교체할 수 있습니다. 동일한 인터페이스를 가진 서로 다른 전략들을 정의한 다음, 컨텍스트 클래스가 어떤 전략을 사용할지 선택하게 하세요. 이를 통해 기존 코드를 변경하지 않고도 새로운 알고리즘으로 확장하기 쉽고 유연한 코드를 만들 수 있습니다.

challenge icon

챌린지

중급

우리의 쇼핑 시스템을 위한 새로운 BitcoinPayment 전략을 구현하세요.

여러분의 과제는 다음과 같습니다:

  1. PaymentStrategy를 구현하는 BitcoinPayment 클래스를 생성합니다.
    • 생성자에서 wallet_address를 받아야 합니다.
    • pay 메서드는 정확히 다음과 같이 출력해야 합니다: Paying $X using Bitcoin wallet: Y (여기서 X는 금액, Y는 지갑 주소입니다)
    • pay 메서드는 출력 후 True를 반환해야 합니다.
  2. 다음과 같은 작업을 수행하는 main 함수를 작성합니다:
    • 쇼핑 카트를 생성합니다.
    • 가격이 $1200인 노트북과 $100인 헤드폰을 카트에 추가합니다.
    • 지갑 주소가 "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"인 BitcoinPayment를 생성합니다.
    • 이 결제 전략을 카트에 설정합니다.
    • checkout 메서드를 호출합니다.

시작 코드의 하단에는 이미 if __name__ == "__main__":이 포함되어 있으므로 직접 추가할 필요가 없습니다. 이것은 파일이 직접 실행될 때만 main() 함수가 실행되도록 보장하는 Python의 관례입니다(다른 모듈에 의해 임포트될 때는 실행되지 않음). 단순히 main() 함수를 정의하면 제공된 블록이 자동으로 이를 호출할 것입니다.

레슨 예제에서 보여준 것과 동일한 구조를 따르세요.

치트 시트

전략 패턴(Strategy Pattern)은 알고리즘 군을 정의하고, 각각을 캡슐화하여 상호 교환이 가능하게 만듭니다. 클라이언트 코드를 변경하지 않고도 런타임에 알고리즘을 전환할 수 있습니다.

동일한 인터페이스를 가진 전략 클래스들을 생성합니다:

class CreditCard:
    def pay(self, amount):
        return f"Paid ${amount} with Credit Card"

class PayPal:
    def pay(self, amount):
        return f"Paid ${amount} with PayPal"

class Bitcoin:
    def pay(self, amount):
        return f"Paid ${amount} with Bitcoin"

전략을 사용하는 컨텍스트 클래스를 생성합니다:

class ShoppingCart:
    def __init__(self):
        self.total = 0
        self.payment_strategy = None
    
    def add_item(self, price):
        self.total += price
    
    def set_payment_strategy(self, strategy):
        self.payment_strategy = strategy
    
    def checkout(self):
        return self.payment_strategy.pay(self.total)

전략 패턴을 사용합니다:

cart = ShoppingCart()
cart.add_item(50)
cart.add_item(30)

# 신용카드 전략 사용
cart.set_payment_strategy(CreditCard())
print(cart.checkout())

# PayPal 전략으로 전환
cart.set_payment_strategy(PayPal())
print(cart.checkout())

정렬 전략을 사용한 또 다른 예시입니다:

class BubbleSort:
    def sort(self, data):
        return f"Bubble sorted: {sorted(data)}"

class QuickSort:
    def sort(self, data):
        return f"Quick sorted: {sorted(data)}"

class Sorter:
    def __init__(self, strategy):
        self.strategy = strategy
    
    def set_strategy(self, strategy):
        self.strategy = strategy
    
    def sort_data(self, data):
        return self.strategy.sort(data)

직접 해보기

from abc import ABC, abstractmethod

class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

class CreditCardPayment(PaymentStrategy):
    def __init__(self, card_number, expiry_date, cvv):
        self.card_number = card_number
        self.expiry_date = expiry_date
        self.cvv = cvv
        
    def pay(self, amount):
        print(f"Paying ${amount} using Credit Card: {self.card_number}")
        return True

class PayPalPayment(PaymentStrategy):
    def __init__(self, email, password):
        self.email = email
        self.password = password
        
    def pay(self, amount):
        print(f"Paying ${amount} using PayPal account: {self.email}")
        return True

class ShoppingCart:
    def __init__(self):
        self.items = []
        self.payment_strategy = None
    
    def add_item(self, item, price):
        self.items.append({"item": item, "price": price})
    
    def set_payment_strategy(self, payment_strategy):
        self.payment_strategy = payment_strategy
    
    def checkout(self):
        total = sum(item["price"] for item in self.items)
        if self.payment_strategy:
            return self.payment_strategy.pay(total)
        else:
            raise ValueError("No payment strategy set")

# 여기에 BitcoinPayment 전략 클래스를 생성하세요


if __name__ == "__main__":
    main()
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Object Oriented Programming의 모든 레슨