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

独立性可以数:一个方法要接收多少个外部对象——实测强依赖版 6 个参数、打包成一组数据后 1 个;依赖从 6 降到 1,等于少知道 5 个类。

📝 本节和前面几节的关系

10.3 去掉重复,这一节处理另一个成本来源:耦合。改一个东西,会不会连带改一片。

一、独立性怎么量

看参数个数:一个方法要 6 个外部对象,说明它认识 6 个类。 看 import 个数:一个文件 import 了 15 个模块,它就跑不远。 看直接访问别人字段的次数:越多,越怕对方改。 这三个数都能数,所以独立性不是感觉。

二、实测:参数从 6 降到 1

强依赖版:make(self, reader, book, loan, fine, cashier, printer)——6 个参数。 弱依赖版:make(self, rows)——1 个参数,把要的数据打包成一组传进来。 依赖从 6 降到 1——调用方不用再知道那 5 个类的存在。

三、打包不是万能药

打包只是把依赖从【方法级】移到【调用方】:调用方还是要造那 6 个对象。 真正的好处是:Report 这个类以后谁都能用,不用带着 6 个类一起搬。 所以判断标准是:这个类将来要不要单独拿走?要,就该打包。

四、独立性的两个误区

以为参数少就一定好:把 6 个参数塞进 1 个没人看得懂的 dict,那叫藏依赖。 以为独立性越高越好:过度拆分会让调用方拼装成本上升,总成本反而变高。 所以目标是【刚好够独立】:这个类能单独测、能单独拿走,就够了。

五、动手 Demo:设计目标之二:提高构件的独立性

用 ast 读出两个版本的方法参数个数(参数就是依赖)。 对比强依赖版与打包版的差别。

import ast

A = """
class Report:
    def make(self, reader, book, loan, fine, cashier, printer):
        return 0
"""
B = """
class Report:
    def make(self, rows):
        return 0
"""

def params(code):
    for n in ast.walk(ast.parse(code)):
        if isinstance(n, ast.FunctionDef):
            return [a.arg for a in n.args.args if a.arg != "self"]

print(len(params(A)), len(params(B)))   # 6 1

实跑输出:

--------------------------------------------------------------------
设计目标之二:提高构件的独立性
--------------------------------------------------------------------

  独立性可以量:**一个方法要接收多少个外部对象。**实测两个类:

  类                   参数(=依赖)                                 个数
  -------------------------------------------------------------------------
  Report(强依赖)     reader/book/loan/fine/cashier/printer     6
  Report(弱依赖)     rows                                           1

      强依赖版的依赖              6 个(reader/book/loan/fine/cashier/printer)
      弱依赖版的依赖              1 个(rows)
      依赖从 6 个降到            1 个

  **参数个数就是依赖个数**——6 个参数意味着调用方必须知道 6 个类。
  **把它们打包成一组数据传进来,依赖从 6 降到 1。**
  **这就是【提高独立性】的具体动作**:不是少写代码,是少知道别人。

实测:强依赖版 6 个参数(reader/book/loan/fine/cashier/printer),弱依赖版 1 个。 参数个数就是依赖个数——依赖从 6 降到 1,等于少知道 5 个类。 但打包只是把依赖移到调用方,真正的好处是这个类能单独拿走。

30 秒实验

  1. 数一数你项目里参数最多的那个方法,它认识几个类。
  2. 找出一个文件 import 超过 10 个模块的地方,看能不能分层。

常见误区

  1. 以为参数少就一定独立。把 6 个塞进一个 dict 只是藏依赖。
  2. 以为越独立越好。过度拆分让调用方拼装成本上升。
自测三问(点开对答案) 1. 独立性可以用哪三个数来量? —— 方法参数个数、文件 import 个数、直接访问别人字段的次数。 2. 实测参数从几个降到几个? —— 从 6 个(6 个外部对象)降到 1 个(一组数据)。 3. 打包的局限是什么? —— 依赖只是移到调用方;真正的好处是这个类能单独拿起走。

相关笔记