副标题: 90%的人不知道,策略模式能让你轻松切换算法而不修改代码
痛点:为什么你的if-else总是越写越长?
2025年某支付系统,每种支付方式都要写一大段代码。问题出在哪?工程师没有使用策略模式封装不同算法。
真相:策略模式将算法族封装成独立类,让算法可互换。
| 模式 | 核心目的 | 典型场景 |
| 策略 | 算法族互换 | 支付方式、排序算法 |
| 命令 | 请求封装 | 撤销/重做、任务队列 |
一、策略模式
1.1 什么是策略模式
定义一系列算法,将每个算法封装起来,并使它们可以互换。
from abc import ABC, abstractmethod
策略接口
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount):
pass
具体策略
class CreditCardPayment(PaymentStrategy):
def __init__(self, card_number):
self.card_number = card_number
def pay(self, amount):
print(f"使用信用卡 {self.card_number} 支付 ${amount}")
class PayPalPayment(PaymentStrategy):
def __init__(self, email):
self.email = email
def pay(self, amount):
print(f"使用 PayPal {self.email} 支付 ${amount}")
class CryptoPayment(PaymentStrategy):
def __init__(self, wallet):
self.wallet = wallet
def pay(self, amount):
print(f"使用加密货币 {self.wallet} 支付 ${amount}")
上下文
class ShoppingCart:
def __init__(self):
self.items = []
self._payment_strategy = None
def add_item(self, item, price):
self.items.append((item, price))
def set_payment_strategy(self, strategy):
self._payment_strategy = strategy
def checkout(self):
total = sum(price for _, price in self.items)
print(f"购物车总计: ${total}")
self._payment_strategy.pay(total)
使用
cart = ShoppingCart()
cart.add_item("书", 20)
cart.add_item("笔", 5)
cart.set_payment_strategy(CreditCardPayment("1234-5678-9012-3456"))
cart.checkout()
cart.set_payment_strategy(PayPalPayment("user@example.com"))
cart.checkout()
1.2 策略模式的优势
# 不使用策略模式(if-else地狱)
def calculate_price(price, discount_type):
if discount_type == 'member':
return price * 0.9
elif discount_type == 'vip':
return price * 0.8
elif discount_type == 'promo':
return price * 0.7
else:
return price
使用策略模式
class DiscountStrategy(ABC):
@abstractmethod
def calculate(self, price):
pass
class MemberDiscount(DiscountStrategy):
def calculate(self, price):
return price * 0.9
class VIPDiscount(DiscountStrategy):
def calculate(self, price):
return price * 0.8
class PromoDiscount(DiscountStrategy):
def calculate(self, price):
return price * 0.7
class PriceCalculator:
def __init__(self, strategy):
self._strategy = strategy
def calculate(self, price):
return self._strategy.calculate(price)
使用
calculator = PriceCalculator(MemberDiscount())
print(calculator.calculate(100)) # 90.0
calculator._strategy = VIPDiscount()
print(calculator.calculate(100)) # 80.0
1.3 策略模式与函数
# 策略也可以用函数实现
def member_discount(price):
return price * 0.9
def vip_discount(price):
return price * 0.8
def promo_discount(price):
return price * 0.7
class PriceCalculator:
def __init__(self, discount_func):
self._discount_func = discount_func
def calculate(self, price):
return self._discount_func(price)
使用
calculator = PriceCalculator(member_discount)
print(calculator.calculate(100)) # 90.0
calculator._discount_func = vip_discount
print(calculator.calculate(100)) # 80.0
二、命令模式
2.1 什么是命令模式
将请求封装为对象,使你可以用不同的请求对客户进行参数化。
from abc import ABC, abstractmethod
命令接口
class Command(ABC):
@abstractmethod
def execute(self):
pass
@abstractmethod
def undo(self):
pass
接收者
class Light:
def __init__(self, location):
self.location = location
self.is_on = False
def on(self):
self.is_on = True
print(f"{self.location} 灯已开启")
def off(self):
self.is_on = False
print(f"{self.location} 灯已关闭")
具体命令
class LightOnCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.on()
def undo(self):
self.light.off()
class LightOffCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.off()
def undo(self):
self.light.on()
调用者
class RemoteControl:
def __init__(self):
self._commands = {}
self._history = []
def set_command(self, slot, command):
self._commands[slot] = command
def press_button(self, slot):
if slot in self._commands:
self._commands[slot].execute()
self._history.append(self._commands[slot])
def press_undo(self):
if self._history:
command = self._history.pop()
command.undo()
使用
living_room_light = Light("客厅")
bedroom_light = Light("卧室")
light_on = LightOnCommand(living_room_light)
light_off = LightOffCommand(living_room_light)
remote = RemoteControl()
remote.set_command(1, light_on)
remote.set_command(2, light_off)
remote.press_button(1) # 客厅 灯已开启
remote.press_button(2) # 客厅 灯已关闭
remote.press_undo() # 客厅 灯已开启
2.2 命令队列
class CommandQueue:
"""命令队列"""
def __init__(self):
self._queue = []
self._executed = []
def add_command(self, command):
self._queue.append(command)
def execute_all(self):
while self._queue:
command = self._queue.pop(0)
command.execute()
self._executed.append(command)
def undo_all(self):
while self._executed:
command = self._executed.pop()
command.undo()
使用
queue = CommandQueue()
queue.add_command(LightOnCommand(living_room_light))
queue.add_command(LightOnCommand(bedroom_light))
queue.add_command(LightOffCommand(living_room_light))
queue.execute_all()
客厅 灯已开启
卧室 灯已开启
客厅 灯已关闭
queue.undo_all()
客厅 灯已开启
卧室 灯已关闭
客厅 灯已关闭
2.3 宏命令
class MacroCommand(Command):
"""宏命令:组合多个命令"""
def __init__(self, commands):
self._commands = commands
def execute(self):
for command in self._commands:
command.execute()
def undo(self):
for command in reversed(self._commands):
command.undo()
使用
all_lights_on = MacroCommand([
LightOnCommand(living_room_light),
LightOnCommand(bedroom_light),
LightOnCommand(KitchenLight("厨房"))
])
all_lights_on.execute()
all_lights_on.undo()
三、实战案例
3.1 排序策略
from typing import List, Callable
class SortStrategy:
def sort(self, data: List) -> List:
raise NotImplementedError
class QuickSort(SortStrategy):
def sort(self, data: List) -> List:
if len(data) <= 1:
return data
pivot = data[len(data) // 2]
left = [x for x in data if x < pivot]
middle = [x for x in data if x == pivot]
right = [x for x in data if x > pivot]
return self.sort(left) + middle + self.sort(right)
class MergeSort(SortStrategy):
def sort(self, data: List) -> List:
if len(data) <= 1:
return data
mid = len(data) // 2
left = self.sort(data[:mid])
right = self.sort(data[mid:])
return self._merge(left, right)
def _merge(self, left: List, right: List) -> List:
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result.extend(left[i:])
result.extend(right[j:])
return result
class Sorter:
def __init__(self, strategy: SortStrategy):
self._strategy = strategy
def sort(self, data: List) -> List:
return self._strategy.sort(data.copy())
使用
data = [5, 2, 8, 1, 9, 3]
sorter = Sorter(QuickSort())
print(sorter.sort(data)) # [1, 2, 3, 5, 8, 9]
sorter._strategy = MergeSort()
print(sorter.sort(data)) # [1, 2, 3, 5, 8, 9]
3.2 支付策略
from abc import ABC, abstractmethod
class PaymentMethod(ABC):
@abstractmethod
def pay(self, amount: float) -> bool:
pass
@abstractmethod
def refund(self, amount: float) -> bool:
pass
class CreditCard(PaymentMethod):
def __init__(self, card_info):
self.card_info = card_info
self.balance = 0
def pay(self, amount: float) -> bool:
print(f"信用卡支付: ${amount}")
self.balance -= amount
return True
def refund(self, amount: float) -> bool:
print(f"信用卡退款: ${amount}")
self.balance += amount
return True
class Alipay(PaymentMethod):
def __init__(self, account):
self.account = account
def pay(self, amount: float) -> bool:
print(f"支付宝支付: ${amount}")
return True
def refund(self, amount: float) -> bool:
print(f"支付宝退款: ${amount}")
return True
class PaymentContext:
def __init__(self):
self._method = None
self._transactions = []
def set_payment_method(self, method: PaymentMethod):
self._method = method
def pay(self, amount: float) -> bool:
if self._method:
result = self._method.pay(amount)
self._transactions.append(('pay', amount, result))
return result
raise ValueError("未设置支付方式")
def refund(self, amount: float) -> bool:
if self._method:
result = self._method.refund(amount)
self._transactions.append(('refund', amount, result))
return result
raise ValueError("未设置支付方式")
使用
payment = PaymentContext()
payment.set_payment_method(CreditCard("1234-5678"))
payment.pay(100)
payment.refund(50)
payment.set_payment_method(Alipay("user@example.com"))
payment.pay(200)
3.3 编辑器命令
class Editor:
def __init__(self):
self._text = ""
self._history = []
self._position = 0
def insert(self, text):
self._text = self._text[:self._position] + text + self._text[self._position:]
self._position += len(text)
def delete(self, length):
deleted = self._text[self._position:self._position + length]
self._text = self._text[:self._position] + self._text[self._position + length:]
return deleted
def get_text(self):
return self._text
class Command(ABC):
@abstractmethod
def execute(self):
pass
@abstractmethod
def undo(self):
pass
class InsertCommand(Command):
def __init__(self, editor, text):
self.editor = editor
self.text = text
self.position = None
def execute(self):
self.position = self.editor._position
self.editor.insert(self.text)
def undo(self):
self.editor._text = (
self.editor._text[:self.position] +
self.editor._text[self.position + len(self.text):]
)
self.editor._position = self.position
class DeleteCommand(Command):
def __init__(self, editor, length):
self.editor = editor
self.length = length
self.deleted_text = None
self.position = None
def execute(self):
self.position = self.editor._position
self.deleted_text = self.editor.delete(self.length)
def undo(self):
self.editor._text = (
self.editor._text[:self.position] +
self.deleted_text +
self.editor._text[self.position:]
)
self.editor._position = self.position
class EditorCommandManager:
def __init__(self, editor):
self.editor = editor
self._history = []
def execute(self, command: Command):
command.execute()
self._history.append(command)
def undo(self):
if self._history:
command = self._history.pop()
command.undo()
使用
editor = Editor()
manager = EditorCommandManager(editor)
manager.execute(InsertCommand(editor, "Hello"))
manager.execute(InsertCommand(editor, " World"))
print(editor.get_text()) # Hello World
manager.undo()
print(editor.get_text()) # Hello
manager.undo()
print(editor.get_text()) # (空)
四、模式对比
4.1 策略 vs 状态
# 策略模式:客户端主动选择算法
class DiscountStrategy:
def calculate(self, price):
pass
状态模式:对象内部状态改变行为
class OrderState:
def process(self, order):
pass
class PendingState(OrderState):
def process(self, order):
order.status = 'processing'
class ProcessingState(OrderState):
def process(self, order):
order.status = 'completed'
class Order:
def __init__(self):
self.state = PendingState()
self.status = 'pending'
def process(self):
self.state.process(self)
4.2 命令 vs 策略
# 命令模式:封装请求,支持撤销
class Command:
def execute(self):
pass
def undo(self):
pass
策略模式:封装算法,支持互换
class Strategy:
def execute(self):
pass
五、最佳实践
| 场景 | 推荐模式 |
| 多种算法可选 | 策略 |
| 需要撤销/重做 | 命令 |
| 请求参数化 | 命令 |
| 算法动态切换 | 策略 |
核心原则:
-
●策略模式解耦算法和客户端-
●命令模式封装请求为对象-
●支持撤销是命令模式的独特优势-
结语
关键洞察:
-
●策略模式:算法族互换-
●命令模式:请求封装 + 撤销-
●两者都能解耦,但应用场景不同-
●优先使用组合而非继承-
互动
-
1.你用策略模式做过什么?-
2.命令模式的撤销功能有用吗?-
3.策略和状态模式容易混淆吗?-
版本: V1.0 | 2026-05-26 | Python设计模式系列
📚 推荐阅读
📝 摘要:今天深入学习静态代码分析技术,这是安全审计的核心技能。从 Python AST 模块到检测模式设计,收获满满!
发布于 202603
01-Python 环境搭建与第一个脚本
发布于 202603
【优化】Python代码优化与调试技巧
发布于 202603
KEYWORDS
IL, Python, AI, 函数, 类
💡 如果你觉得这篇文章有帮助,请点个在看,分享给更多需要的人!
📝 关注我,获取更多实用干货~
🤝 有问题欢迎评论区留言交流!