📄 一句话概括
职责分好之后,没有一个类需要懂业务全貌——实测上帝类要知道 8 件事,拆分后最多的一个类只要 3 件,但合起来什么都能干。
📝 本节和前面几节的关系
10.7 讲了分工的手感,这一节讲分工之后得到什么。
一、上帝类的问题
一个类知道 8 件事(额度、在不在架、借出日、应还日、罚款标准、逾期天数、是否已缴、通知谁)。 它能干所有事,但没有一件是它的专长。 最要命的是不能单独测:测罚款得先造出读者、书、借阅记录。
二、实测:8 件降到 3 件
拆成 5 个类:Reader(额度)、Book(在架)、Loan(三天日期)、Fine(标准与是否已缴)、Notifier(通知谁)。
上帝类要知道 8 件,拆分后没有一个类超过 3 件。
加一个通知渠道:上帝类要改那个唯一的类(等于改全部),拆分后只改 Notifier。
三、【奇妙】在哪
没有一个类懂业务全貌,但合起来什么都能干——这就是分工的奇妙。 每个人只管自己那一小块,接口对上就行,像一家公司而不是一个人。 所以 7.6 说业务本身就是一堆对象在分工——这句话在代码里应验了。
四、代价也要认
看一个功能要跳好几个类,读起来累。 所以要靠时序图和文档补回来(第八章那两张图正是干这个的)。 还有一个隐形成本:类多了,找东西变难——包和命名要跟上。
五、动手 Demo:进行了职责分配的软件创建的奇妙世界
对比上帝类与拆分后:类个数、单个类要知道的件数、加需求改哪里、能不能单测。 看【单个类要知道的事】降了多少。
god = ["读者额度", "书在不在架", "借出日", "应还日", "罚款标准",
"逾期天数", "是否已缴", "通知谁"]
split = {"Reader": ["额度"], "Book": ["在不在架"],
"Loan": ["借出日", "应还日", "逾期天数"],
"Fine": ["罚款标准", "是否已缴"], "Notifier": ["通知谁"]}
print(len(god), max(len(v) for v in split.values())) # 8 3
实跑输出:
--------------------------------------------------------------------
进行了职责分配的软件创建的奇妙世界
--------------------------------------------------------------------
职责分好之后,**每个类需要知道的【全局信息】变少了。**实测对比:
对比项 上帝类 职责分配后
---------------------------------------------------------------
类个数 1 5
单个类要知道的事 8 最多 3 件
加一个通知渠道改哪 改 1 个类(但它是全部) 改 Notifier
能单独测吗 不能 能
上帝类要知道的事 8 件
拆分后最多 3 件
【奇妙】在哪 8 件 → 3 件
**同一个功能,上帝类要知道 8 件事,拆分后没有一个类超过 3 件。**
**这就是【奇妙世界】的含义**:**没有一个类需要懂业务全貌**,但合起来什么都能干。
**代价是**:看一个功能要跳好几个类,**所以得靠时序图和文档补回来。**
实测:上帝类要知道 8 件事,拆分后最多的类只要 3 件。 加一个通知渠道:上帝类改那唯一的类(等于全改),拆分后只改 Notifier。 代价是看一个功能要跳好几个类,得靠时序图和文档补。
30 秒实验
- 找出你项目里的一个上帝类,数它要知道几件事。
- 按职责把它拆一次,看看加一个新需求能只改一个类吗。
常见误区
- 以为一个类干所有事最省心。它不能单测、不能复用、不敢改。
- 以为拆分没有代价。看一个功能要跳好几个类,得靠图和文档补。
自测三问(点开对答案)
1. 上帝类最大的问题是什么? —— 知道 8 件事、能干所有事但没有专长,且不能单独测试。 2. 实测降了多少? —— 上帝类 8 件,拆分后最多的类 3 件;加通知渠道只改 Notifier。 3. 【奇妙】在哪、代价是什么? —— 没有一个类懂全貌但合起来什么都能干;代价是读一个功能要跳好几个类。- ☐ COLUMN 当今的OOP 执行时不受类约束的JavaScript
相关笔记
- 面向对象设计的【感觉】是拟人化和职责分配 — 怎么分工
- 为何化为了通用的归纳整理法 — 业务本身就是分工
- 使用时序图和通信图表示动作 — 跳类看功能靠它
- 🧩 面向对象是怎样工作的 · 索引