🧩 第三章 理解OOP:编程语言的历史
📄 一句话概括

复制三份 vs 提成函数:改动点从 3 处降到 1 处——子程序的价值不在少写,在只有一个地方能改。

📝 本节和前面几节的关系

3.5 讲流程,这一节讲复用——这是结构化编程交给 OOP 的第一笔遗产。

一、抄三遍的代价

同一段逻辑在三个地方各抄一遍:改一次需求,要动三处。 漏一处,就是一个隐藏的 bug——而且往往要到上线才被发现。 更麻烦的是,三处会慢慢长得不一样——因为每次改的人不同、改的时间不同。

二、提成函数

提成函数之后:改动点从 3 处降到 1 处,漏改的风险直接消失。 实测:税率从 0.13 改成 0.09,复制版要动 3 处,函数版只动 1 处。 子程序的价值不在【少写几行】,在【只有一个地方能改】。 这就是可维护性的全部基础。

三、代价另一面

函数也不是越多越好。 十个函数各自只被调一次、名字还起不清——那不叫模块化,叫碎片化。 判断标准:这段逻辑会不会被用第二次?会不会独立变化?两个都不会,就别急着提。

四、这条规矩放大到类

把【提取重复】从函数这一级放大到类这一级,就是第 10 章讲的【去除重复】。 把【只留一个入口】放大,就是封装。 所以结构化编程不是被 OOP 取代了,是被 OOP 继承并放大了。

五、动手 Demo:提高子程序的独立性,强化可维护性

同一段算税逻辑,一种抄三份、一种提成函数。 数一数税率改动时要动几处。

copies = ["x * 0.13", "x * 0.13", "x * 0.13"]

def tax(x):
    return x * 0.13

callers = ["tax(a)", "tax(b)", "tax(c)"]
print("复制版:改动点", len(copies))
print("函数版:改动点", 1)
print("调用处不用改", len(callers))

实跑输出:

--------------------------------------------------------------------
提高子程序的独立性,强化可维护性
--------------------------------------------------------------------

  同一段逻辑在三个地方各抄一遍,会发生什么?
  实测:**改一次需求,要动三处;漏一处,就是一个隐藏的 bug。**

      # 抄了三遍(伪代码)
      # 算税:x * 0.13      ← 第 1 处
      # 算税:x * 0.13      ← 第 2 处
      # 算税:x * 0.13      ← 第 3 处

      # 提成子程序
      def tax(x): return x * 0.13
      # 三处都改成 tax(x)

                         复制三份     提成函数
  ---------------------------------------------
  税率改成 0.09 要动     3 处         1 处
  漏改的风险             存在         不存在
  谁负责这段逻辑         三处各自     函数一处

  **子程序的价值不在【少写几行】,在【只有一个地方能改】。**
  这一条听起来简单,**但它是可维护性的全部基础**——
  第 10 章讲的【去除重复】,就是这条规矩放大到类这一级。

  顺便说一个代价:**函数也不是越多越好。**
  十个函数各自只被调一次、名字还起不清,**那不叫模块化,叫碎片化。**

实测:改动点从 3 处降到 1 处,三处调用一个字不用改。 子程序的价值不在少写几行,在【只有一个地方能改】。

30 秒实验

  1. 在你的代码里搜一段重复三次以上的逻辑,试着提成函数。
  2. 反过来找几个只被调一次的小函数,看它们是不是碎片化。

常见误区

  1. 以为提函数只是为了少写代码。核心价值是改一处。
  2. 以为函数越细越好。只调一次还起不清名字的,是碎片。
自测三问(点开对答案) 1. 复制三份的代价是什么? —— 改一次要动三处,漏一处就是隐藏 bug;而且三份会慢慢长得不一样。 2. 子程序真正的价值在哪? —— 不在少写几行,在只有一个地方能改——这是可维护性的全部基础。 3. 函数越多越好吗? —— 不是。只被调一次、名字还起不清的函数是碎片化,不是模块化。

相关笔记