策略、模板方法与 Pydantic
三个考点串一条线:策略模式在 Python 里是传函数,模板方法靠 ABC 定义骨架,Pydantic 是数据建模的事实标准。分别答清楚,再对比。
策略模式:函数即策略
策略的本意:算法可替换,调用方不感知。Java 要接口加实现类,Python 直接传函数:
def price_regular(items): # 策略 1
return sum(items)
def price_vip(items): # 策略 2
return sum(items) * 0.8
def checkout(items, pricing): # 策略注入
return pricing(items)
checkout(items, price_vip) # 换策略 = 换函数- 函数是一等公民,“策略对象”就是函数本身,不需要策略类
- 需要带参策略时用闭包或
functools.partial固化参数 - 一组策略需要名字映射时用 dict 查表(strategy registry),比 if-elif 链干净
PRICING = {"regular": price_regular, "vip": price_vip}
checkout(items, PRICING[user.tier])模板方法:ABC 定义骨架
模板方法的本意:算法骨架固定,步骤可变,子类实现步骤。Python 用抽象基类表达:
from abc import ABC, abstractmethod
class DataImporter(ABC):
def import_data(self, source): # 模板方法: 骨架固定
data = self._fetch(source) # 步骤 1
cleaned = self._clean(data) # 步骤 2
self._save(cleaned) # 步骤 3
@abstractmethod
def _fetch(self, source): ...
@abstractmethod
def _clean(self, data): ...
def _save(self, data): # 钩子: 有默认实现, 可覆盖
db.insert(data)
class CsvImporter(DataImporter): # 只实现步骤, 不碰骨架
def _fetch(self, source): return read_csv(source)
def _clean(self, data): return drop_na(data)要点:import_data 骨架在父类,子类只填步骤;abstractmethod 强制子类实现。对比策略模式:模板方法固定骨架换步骤(继承),策略固定接口换算法(组合)。
ABC 与 Protocol 再对比
| 维度 | ABC(模板方法) | Protocol(策略) |
|---|---|---|
| 关系 | 继承(is-a) | 结构匹配(acts-as) |
| 强制实现 | 编译期/实例化报错 | 类型检查器提示 |
| 适用 | 骨架复用 | 能力约定 |
一句话:要复用骨架用 ABC,要约定能力用 Protocol。策略模式用 Protocol 标注更 Pythonic。
Pydantic:数据建模
Pydantic 是 FastAPI 的数据层,也是 Python 数据建模的事实标准:
from pydantic import BaseModel, Field
class Order(BaseModel):
id: int
user_id: int = Field(gt=0)
items: list[str]
total: float = Field(ge=0)
order = Order.model_validate(payload) # 校验 + 转换
json_str = order.model_dump_json() # 序列化与设计模式的关系:
- DTO(数据传输对象):FastAPI 的请求/响应模型就是 DTO,隔离内部模型与外部契约
- Builder 的替代:
model_copy(update=...)和 dataclasses 的 replace 处理“部分修改”场景,比 Builder 类轻得多 - 校验即防御:边界在入口校验,业务层拿到的是合法数据(Fail Fast)
分层实践:请求模型(入参校验)→ 领域模型(业务逻辑)→ 响应模型(出参契约),用 model_validate 转换,三层职责分开。
面试追问
- Python 的策略模式怎么写? 传函数。带参策略用闭包或 partial,多策略用 dict 查表。不需要策略类
- 模板方法和策略的区别? 模板方法继承固定骨架换步骤;策略组合注入换算法。骨架复用用模板方法
- ABC 和 Protocol 怎么选? 复用骨架用 ABC,约定能力用 Protocol。策略标注用 Protocol
- Pydantic 在 FastAPI 里干什么? 请求/响应模型:校验入参、序列化出参。DTO 模式
- 模型分层怎么分? 请求模型、领域模型、响应模型三层,边界校验,内部隔离