Menu
CoddyTech

策略模式

本课属于 Coddy Python 学习旅程的“面向对象编程”单元。第 48 课,共 64 课。

策略模式定义了一组算法,将每个算法封装起来,并使它们可以互换。你可以在运行时切换算法,而无需更改客户端代码。

下面是用于不同支付方式的简单策略类:

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]

要点:策略模式让你能在运行时切换算法。用相同的接口定义不同的策略,然后让上下文类选择要使用哪一种。这样,你的代码就更灵活,也更容易通过添加新算法来扩展,而无需修改现有代码。

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__":。你无需自行添加。这是一种 Python 约定,用于确保只有在直接运行文件时(而不是由其他模块导入时),才会运行你的 main() 函数。只需定义你的 main() 函数,提供的代码块就会自动调用它。

按照课中示例所示的相同结构完成。

亲手试试

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自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Python 在线编译器