🧩 第十章 面向对象设计:拟人化和职责分配
📄 一句话概括

重复不一定是整段复制,更多是同几行出现三次——实测 12 行代码里 3 种重复行占了 9 行;但长得像不等于重复,能不能一起改才算。

📝 本节和前面几节的关系

10.2 说了重心在改动成本,重复正是改动成本的最大来源——改一处要改三处。

一、重复的三种形态

整段复制:最明显,一眼能看出。 同样几行出现三次:最隐蔽,实测 3 种行各出现 3 次,占了 9 行。 结构重复:代码不一样但形状一样(三个子类各写一遍同样的校验)。

二、实测:12 行里 9 行是重复的

三个类各写一遍 if rate < 0: raise ...、self.rate = rate。 3 种重复行各自出现 3 次,合计 9 行——占 12 行的 75%。 每种只留一份是 6 行,加上三处调用约 9 行,看上去省得不多,但改动点从 3 处变 1 处。

三、关键判断:它们会不会一起改

会一起改,才叫重复。 那三处校验规则一变,三处都得改——这是真重复。 只是长得像、但会各自演化,那叫巧合。 硬合并反而害了它们:一个改了另一个不该改。 所以去重之前先问一句:这两个东西将来会一起变吗?

四、去重的三种手法

提取方法:把重复的几行提成一个函数。 提到父类:几个类共有的部分上移到父类(4.9 的继承)。 参数化:把不同的那一部分做成参数,剩下的共用。 手法选择看重复的粒度:几行用提取方法,几类共有用父类,只差一点用参数化。

五、动手 Demo:设计目标之一:去除重复

用 Counter 扫一段代码,找出出现不止一次的行。 数出重复行占了总行数的多少。

from collections import Counter
src = ["if rate < 0:", "    raise ValueError('rate')",
       "self.name = name", "self.rate = rate",
       "if rate < 0:", "    raise ValueError('rate')",
       "self.title = title", "self.rate = rate",
       "if rate < 0:", "    raise ValueError('rate')",
       "self.code = code", "self.rate = rate"]

dup = [(k, v) for k, v in Counter(src).items() if v > 1]
print(len(src), len(dup), sum(v for k, v in dup))   # 12 3 9

实跑输出:

--------------------------------------------------------------------
设计目标之一:去除重复
--------------------------------------------------------------------

  重复不一定是整段复制,**更多是【同样的几行出现三次】。**实测扫描:

  重复的行                     出现次数
  --------------------------------------
  if rate < 0:                 3
  raise ValueError("rate")     3
  self.rate = rate             3

      代码行                      12 行
      重复出现的行                3 种
      重复行占用                  9 行
      每种只留一份                6 行
      加上三处调用                约 9 行

  **3 种重复行占了 9 行**,提取一次就能省掉后面的复制。
  **关键判断**:这三处改的时候是不是要一起改?**是要一起改,才叫重复。**
  **只是长得像但会各自演化,那叫巧合**——硬合并反而害了它们。

实测:12 行里 3 种重复行各出现 3 次,共占 9 行。 每种只留一份是 6 行——省的行数不多,但改动点从 3 处变成 1 处。 判断标准是【会不会一起改】,只是长得像那是巧合。

30 秒实验

  1. 用同样的办法扫你自己的一段文件,找出重复行。
  2. 对每一处重复问一句:它们将来会一起改吗。

常见误区

  1. 以为只有整段复制才叫重复。同几行出现三次更常见也更隐蔽。
  2. 把长得像但各自演化的代码强行合并。那会害了它们。
自测三问(点开对答案) 1. 重复的三种形态? —— 整段复制、同几行出现三次、结构重复(形状一样但代码不同)。 2. 实测重复占多少? —— 12 行里 3 种重复行各 3 次,共 9 行;每种留一份是 6 行。 3. 判断重复的标准是什么? —— 将来会不会一起改——会一起改才是真重复,只是像叫巧合。

相关笔记