📄 一句话概括
同一需求三版:函数版 8 行、类版 12 行、策略版 17 行;函数版加一种最省(2 行),但主函数从 8 行长到 10 行,另两版主函数恒为 2 行——熟练不是会用语法,是知道每一版的代价。
📝 本节和前面几节的关系
12.3 说它不会退场,这一节说怎么才算【熟练】——不是会写,是选得对。
一、实测:同一需求的三种写法
需求:按会员等级打折(none/vip/svip)。 函数版 8 行:一个函数里三条 if。 类版 12 行:一个基类+两个子类+一张表。 策略版 17 行:一个注册表+装饰器,每个折扣一个函数。 三版结果都对,差别只在结构。
二、每版的代价在哪
加一种【员工折扣】之后再看:三版都能加,代价不同。 函数版新增 2 行最省,但主函数从 8 行长到 10 行——改的正是最忙的那个函数。 类版与策略版的主函数恒定 2 行:加东西全写在外面,主函数一个字不动。 策略版要多花 2 行(4 行 vs 2 行),那 2 行买的是【主函数永不改动】。
三、怎么选:看会加几种
只加一两种:函数版就够,短、直白、无抽象负担。 会加到五种以上、还要别人接手:类版或策略版,把变化关在一个地方。 判断依据只有一条:这个地方以后会不会反复来人加东西? 所以【熟练掌握】不是背模式名,是能说清每一版要付什么代价。
四、动手 Demo:将面向对象作为工具熟练掌握
同一需求写三版,各加一种折扣。 用 ast 数行数与 if 条数,用 difflib 数新增行数。
import ast, difflib
V1 = '''def price(kind, amt):
if kind == 'none': return amt
if kind == 'vip': return amt * 0.9
if kind == 'svip': return amt * 0.8
return amt'''
V2 = '''class Rule:
def calc(self, amt): return amt
class Vip(Rule):
def calc(self, amt): return amt * 0.9
class Svip(Rule):
def calc(self, amt): return amt * 0.8
TABLE = {'none': Rule(), 'vip': Vip(), 'svip': Svip()}
def price(kind, amt): return TABLE[kind].calc(amt)'''
def main_lines(src):
f = [x for x in ast.walk(ast.parse(src))
if isinstance(x, ast.FunctionDef) and x.name == 'price'][0]
return f.end_lineno - f.lineno + 1
print(main_lines(V1)) # 8 (加 staff 后变 10)
print(main_lines(V2)) # 2 (加 Staff 类后仍是 2)
实跑输出:
--------------------------------------------------------------------
将面向对象作为工具熟练掌握
--------------------------------------------------------------------
同一个需求(按会员等级打折)写三版,**再各加一种【员工折扣】**,用 difflib 数改动:
写法 总行数 主函数行数 加一种后 主函数 if 新增行
-----------------------------------------------------------------------
函数版 8 8 10 3 2
类版 12 2 2 0 5
策略版 17 2 2 0 4
三种写法的结果都正确 True
总行数最少的 函数版
主函数跟着种类长大的 函数版
加一种新增行最少的 函数版
**三版都对,没有一版全面胜出**——这才是 12.4 说的【作为工具熟练掌握】。
**函数版最短,加一种也最省(2 行)**,**但主函数跟着种类一起长**(8 行→10 行、if 3 条),
**每加一种都要回去改它**——改的地方正是最忙的那个函数。
**类版和策略版的主函数恒定 2 行**:加东西全写在外面,**主函数一个字不动。**
**策略版加一种要 4 行**(比函数版多 2 行),**那 2 行差价买的是【主函数永不改动】。**
**判断依据很实在:这个折扣会加几种?** 只加一两种,函数版就够。
实测:函数版 8 行最短,加一种只多 2 行,但主函数从 8 行长到 10 行。 类版与策略版的主函数恒定 2 行——加东西写在外面,主函数一个字不动。 所以选型不看长短,看【这地方以后会不会反复来人加东西】。
30 秒实验
- 给你项目里一个 if/elif 链数一数:它现在几条分支?一年后会变几条?
- 按【会加几种】这条标准,判断你手上哪个地方该换成类版或策略版。
常见误区
- 以为模式越高级越好。只加一两种时,模式纯粹是负担。
- 以为短就一定好。函数版短,但最忙的那个函数被反复改。
自测三问(点开对答案)
1. 三版各多少行? —— 函数版 8 行、类版 12 行、策略版 17 行,结果都正确。 2. 加一种折扣后差在哪? —— 函数版主函数 8 行→10 行;类版与策略版主函数恒 2 行。 3. 选型的唯一依据? —— 这个地方以后会不会反复来人加东西;会,就把变化关进一个地方。- ☐ 12.5 享受需要动脑的软件开发
相关笔记
- 设计目标之一:去除重复 — 该不该抽出去
- 提高构件独立性的诀窍 — 把变化关起来
- 不存在最好的开发流程 — 同样的取舍逻辑
- 🧩 面向对象是怎样工作的 · 索引