Skip to content

策略组合实践 ​

前置:能区分接口契约与实现,理解函数作为参数和整数分计价;Python 3.10+ 仅用于报价模型。教学范围为函数组合与GoF意图;Python 3.10+。核对日期2026-10-17。示例未执行,本轮没有安装依赖、生成协议代码、启动服务或浏览器预览。完整源码和输入文件见下方「同源完整文件」;推演结论只适用于写明的模型。

完整报价组合程序 ​

完整报价组合程序把折扣和报价校验分离,整数分避免二进制浮点金额误差。普通价、九折和满额减20元各为独立函数;上下文验证策略输出,不执行收费。输入数量和单价不能为负,未知策略显式失败。

策略输出与异常 ​

策略输出与异常可以逐项核对:单价1000分数量3得到普通价3000分、九折2700分;满额门槛是10000分。采用整数除法向下取整是本教学规则,生产税费的舍入方式应单独确定,不能默默继承。

设计模式取舍练习 ​

设计模式取舍练习把满额阈值从10000改为12000,应只改变策略中的阈值,而不改变输入验证。加入返回负数的测试替身,检查上下文是否拒绝非法结果;这验证的是契约,不是多写一个接口。

同源完整文件 ​

以下README含前置、输入、读者自跑步骤、预期结果、失败、恢复与清理;只做静态核对,没有执行。

model.py ​

python
import json
import sys

def regular(total):
    return total

def ten_percent_off(total):
    return total * 90 // 100

def threshold_off(total):
    return total - 2000 if total >= 10000 else total

POLICIES = {'regular': regular, 'discount': ten_percent_off, 'threshold': threshold_off}

def quote(price, quantity, policy):
    if type(price) is not int or type(quantity) is not int or price < 0 or quantity < 0:
        raise ValueError('nonnegative integer cents and quantity required')
    result = policy(price * quantity)
    if type(result) is not int or result < 0:
        raise ValueError('policy violated amount contract')
    return result

if __name__ == '__main__':
    try:
        data = json.load(sys.stdin)
        policy = POLICIES[data['policy']]
        print(json.dumps({'cents': quote(data['price'], data['quantity'], policy)}))
    except (ValueError, TypeError, KeyError) as error:
        print(str(error), file=sys.stderr)
        sys.exit(2)

requirements.txt ​

text
# Python 3.10+ standard library only; no third-party dependency.

README.md ​

md
# 设计模式与变化边界:完整示例

示例未执行。核对日期2026-10-17。教学版本族:函数组合与GoF意图;Python 3.10+。

## 文件与依赖

文件:model.py, requirements.txt。requirements.txt为同源依赖声明;所有代码和配置都随本文展示。本例使用 Python 3.10+ 标准库,无额外运行依赖。

## 输入与前置

前置:理解函数作为参数与策略替换,金额统一用整数分。使用 Python 3.10+,本例只依赖标准库。输入为 price、quantity 和 policy 组成的 JSON 对象;具体报价与错误预期见下节。

读者将来自跑(本轮未执行):在本目录以Python 3.10+读取input.json,PowerShell示意`Get-Content -Raw input.json | python model.py`;Bash示意`python3 model.py < input.json`。把下面输入手工保存为UTF-8文件,输出按预期逐项比较。无需安装依赖,没有服务或网络调用;程序只读标准输入并写标准输出,不改原文件。失败信息写标准错误且退出2。恢复是修正输入后重读,清理只删除自己创建的input.json与输出文件,勿递归删除工作目录。

## 预期结果、失败与恢复

输入 {"price":1000,"quantity":3,"policy":"discount"},预期cents=2700;price=5000 quantity=2 policy=threshold得到8000;未知policy退出2。

失败要保留输入和错误,先与正文的不变量及边界核对。没有真实服务或性能验证,不以这些模型输出证明生产可用性。

## 独立练习

门槛改为12000;分别手算11999、12000分。再向quote注入lambda total: -1。

参考答案:把threshold_off条件改成total>=12000,11999保持11999,12000减2000得10000。注入负数策略会被quote拒绝,说明输入正确仍须检查可替换实现的输出。

先作答,再核对 ​

门槛改为12000;分别手算11999、12000分。再向quote注入lambda total: -1。

逐步参考解答

把threshold_off条件改成total>=12000,11999保持11999,12000减2000得10000。注入负数策略会被quote拒绝,说明输入正确仍须检查可替换实现的输出。

报价管道的失败位置 ​

按单价1000分、数量3、九折计算,原始金额3000,策略返回2700;输入校验与结果校验在不同位置。未知策略应在选择阶段失败,负数结果应在返回前失败。把这两类错误分开,才能判断应修输入还是修策略实现。

查看图表代码

来源与适用边界 ​

继续阅读