🧩 第十二章 熟练掌握面向对象
📄 一句话概括

同一需求三版:函数版 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 秒实验

  1. 给你项目里一个 if/elif 链数一数:它现在几条分支?一年后会变几条?
  2. 按【会加几种】这条标准,判断你手上哪个地方该换成类版或策略版。

常见误区

  1. 以为模式越高级越好。只加一两种时,模式纯粹是负担。
  2. 以为短就一定好。函数版短,但最忙的那个函数被反复改。
自测三问(点开对答案) 1. 三版各多少行? —— 函数版 8 行、类版 12 行、策略版 17 行,结果都正确。 2. 加一种折扣后差在哪? —— 函数版主函数 8 行→10 行;类版与策略版主函数恒 2 行。 3. 选型的唯一依据? —— 这个地方以后会不会反复来人加东西;会,就把变化关进一个地方。

相关笔记