📄 一句话概括
多态就一句:调用方只管喊,谁被喊到谁自己算;价值不在少写几行,在知识放在谁那儿。
📝 本节和前面几节的关系
2.2 分清了个体,这一节讲个体之间怎么协作——这是三大要素里最容易被讲玄的一个。
一、一句话说清多态
total(shapes) 里写 s.area(),它不知道 s 是矩形还是圆。
但每个 s 都知道自己该怎么算——于是同一句调用,落到不同的实现上。
这就是多态的全部,跟【变形】没有半点关系(1.6 说过这条比喻歪得最狠)。
二、if 链 vs 多态
if 链写法:total 里判断类型,分头算。代码集中,但每加一种就要回来改它。
多态写法:total 只管调 area,不管类型。加一种形状,新写一个类就行。
实测对比:从第 3 种到第 10 种形状,if 链要多改 8 次,多态要加 8 个类。
看起来都是 8,差别在【改的是谁】。
三、知识放在哪
if 链写法里,total 必须认识所有图形——它背着全部类型知识。
多态写法里,total 只认识【有 area 的东西】——类型知识散到各个类里。
这是本书反复出现的主题:把知识放在最该待的地方。第 10 章的职责分配讲的就是这件事。
四、多态的前提
多态能成立,靠一条约定:调用必须走方法。 如果有人绕过方法直接改数据(1.2 讲的封装被破坏),多态就失去意义了。 还有一条:方法名和签名要对得上——这正是【接口】和【抽象类】要解决的问题(第 4 章)。
五、动手 Demo:多态让消息的发送方法变得通用
一个 total 函数,对着一组不同形状调同一个方法。
它里面没有一个 if,也不需要知道任何一个形状的名字。
class Rect:
def __init__(self, w, h): self.w, self.h = w, h
def area(self): return self.w * self.h
class Circle:
def __init__(self, r): self.r = r
def area(self): return 3.14159 * self.r * self.r
def total(shapes):
return sum(s.area() for s in shapes)
shapes = [Rect(6, 4), Circle(3)]
print("矩形", Rect(6, 4).area())
print("圆 ", round(Circle(3).area(), 5))
print("合计", round(total(shapes), 5))
实跑输出:
--------------------------------------------------------------------
多态让消息的发送方法变得通用
--------------------------------------------------------------------
一句话:**调用方只管喊【算面积】,谁被喊到谁自己算。**
shapes = [Rect(6, 4), Circle(3)]
total(shapes) → 52.27431
`total` 里**没有一个 if,也不知道自己是哪一种图形**——
它只要求一件事:**你身上有 `area` 这个方法。**
实测两种写法加形状的代价:
if 链写法 多态写法
------------------------------------------------
要改的地方 total 里的 if 新加一个类
第 3 种形状 改 1 处 加 1 个类
第 10 种形状 改 8 次 加 8 个类
total 知道几种 全部 2 种 0 种
**关键不在少写几行,在【知识放在哪】。**
if 链写法里,`total` 必须认识所有图形——**加一种就要回来改它。**
多态写法里,`total` 只认识【有 area 的东西】——**永远不用回来。**
**同一句 `s.area()`,落到两个不同的实现上——这就是多态的全部。**
实测:矩形 24、圆 28.27431、合计 52.27431。
total 里一个 if 都没有——同一句 s.area(),落到两个不同实现上。
30 秒实验
- 给
total加第三种形状,数一数要改哪些文件。 - 把
total改成 if 链写法,再数一次。
常见误区
- 以为多态是【一个东西变成另一个】。它是【同一句调用落到不同实现】。
- 以为多态只是少写代码。它改的是知识放在谁那儿。
自测三问(点开对答案)
1. 用一句话说清多态。 —— 调用方只管喊方法名,谁被喊到谁自己算,同一句调用会落到不同实现上。 2. 多态和 if 链的真正差别在哪? —— 不在代码行数,在知识放在谁那儿:if 链让调用方背着全部类型知识,多态把知识散到各个类里。 3. 多态成立的前提是什么? —— 调用必须走方法(封装不被破坏),且方法名和签名要对得上。- ☐ 下一节(2.4 继承对共同点和不同点进行系统的分类和整理)
相关笔记
- 继承对共同点和不同点进行系统的分类和整理 — 横向之后看纵向
- 原因之二:滥用比喻引起混乱 — 【多态=变形】为什么歪
- 以对象为中心编写软件的开发方法 — 封装是多态的前提
- 🧩 面向对象是怎样工作的 · 索引