【调用端公用化】就是调用方只写一份——加一种形状,调用端一个字不用改。
4.4~4.7 讲完类的三件事,这一节讲第二个要素:同一句调用,不同的实现。
一、五个字的意思
公用=调用端的代码只有一份;私用=各形状的实现各自一份。
def total(shapes): return sum(s.area() for s in shapes)——这一行不知道有几形状、什么形状。
它只要求一件事:你能 area()。这就是 2.3 说的【消息的发送方法变得通用】。
二、实测对比
多态版:total 一行,实测 52.27431(矩形 24 + 圆 28.27431)。
不用多态版:if isinstance(s, Rect): s.area_rect()、elif isinstance(s, Circle): s.area_circle()。
调用端要写几行:每个形状 2 行 vs 1 行。
调用端知道几种?全部 vs 0 种。
三、差在加形状的那一刻
不用多态:加 2 行分支,而且要回去改那个已经测过的函数。 多态:加 1 个类,调用端 0 改动。 这就是开闭原则的全部内容:对扩展开放(加类),对修改关闭(不动调用端)。 注意:不是多态让程序变短,是多态让【加东西】不再碰【老东西】。
四、注意这不是【变形】
多态不是对象变了形状,是同一个名字在不同对象上有不同的实现。
s.area() 里的 s 一直没变,变的是【谁在响应这一次调用】。
所以多态的本质是【把知识放在谁那儿】——每个形状自己知道自己怎么算。
点开 2.3 会看到同一件事在比喻层面的说法;这里是它在代码里的样子。
五、动手 Demo:三大要素之二——实现调用端公用化的多态
两个形状各自实现 area,调用端只写一句 s.area()。 对比不用多态时要写多少分支。
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)
print(total([Rect(6, 4), Circle(3)]))
实跑输出:
--------------------------------------------------------------------
三大要素之二——实现调用端公用化的多态
--------------------------------------------------------------------
【调用端公用化】这五个字,说的是**调用方的代码只写一份**。
多态版:def total(shapes): return sum(s.area() for s in shapes)
实测 total → 52.27431
不用多态版(思路):
if isinstance(s, Rect): s.area_rect()
elif isinstance(s, Circle): s.area_circle()
不用多态 多态
-----------------------------------------------
调用端要写几行 每个形状 2 行 1 行
加一种形状 加 2 行分支 加 1 个类
调用端知道几种 全部 0 种
**【公用化】这个词很准:调用端是【公用】的,各形状的实现是【私用】的。**
实测两个形状各算各的(24 与 28.27431),**`total` 一个字没改。**
实测:total 一行算出 52.27431(矩形 24 + 圆 28.27431),total 不知道有几个形状、什么形状。
不用多态就要写 if/elif 分支:加一种形状加 2 行,调用端还得回头改。
30 秒实验
- 找一个写着 if isinstance 的函数,把分支搬进各自的类,看调用端还剩几行。
- 数一数【加一种新东西】要在几个文件里改。
常见误区
- 以为多态是对象变形。是同一个名字在不同对象上有不同实现。
- 以为多态只是让代码变短。真正的价值是加东西不碰老代码。
自测三问(点开对答案)
1. 【调用端公用化】是什么意思? —— 调用方的代码只写一份,各形状的实现各自一份——调用端不知道有几种形状。 2. 多态版和 if 分支版差在哪? —— 调用端每形状 2 行 vs 1 行;加一种形状是加 2 行分支(还要改老代码)vs 加 1 个类(调用端不动)。 3. 多态的本质是什么? —— 同一句调用,不同对象有不同实现——把知识放在各自的对象那儿,而不是放在调用方。- ☐ 下一节(4.9 三大要素之三:去除类的重复定义的继承)
相关笔记
- 多态让消息的发送方法变得通用 — 同一件事的比喻版
- 三大要素之三:去除类的重复定义的继承 — 第三个要素
- 以对象为中心编写软件的开发方法 — 谁响应调用
- 🧩 面向对象是怎样工作的 · 索引