📄 一句话概括
拿现实世界打比方能入门,但最好的一条比喻也只对一半——多态跟【变形】没有半点关系,选课记录在现实里根本不是一个【物】。
📝 本节和前面几节的关系
1.5 说结构复杂,这一节说第二个坑:比喻。它比第一个坑更隐蔽,因为它听起来很顺。
一、哪些比喻对得上
对象=现实中的物——大体对得上。内存里确实有一块带类型的数据。 类=分类——也对得上。类就是一份字段与方法的模板。 这两条是入门的好拐杖,用它们是安全的。
二、哪些一对就歪
继承=父子——常对不上。父类成员是复制进来的,不是遗传;而且一个子类可以有两个父亲(多重继承)。 多态=变形——完全不是。它跟变形没有半点关系,只是【同一句调用,落到不同实现上】。 消息=说话——容易想歪。它就是一次普通的函数调用,没有信箱、没有邮差。 歪掉的比喻比没有比喻更糟——因为它会让你在错误的方向上自信。
三、现实里找不到对应物的类
最隐蔽的坑:有些类在现实世界里根本不是【一个东西】。
比如选课系统里的 Enrollment(选课记录)——它既不是学生,也不是课程。
它是两者之间的关系。现实里那叫一张单子,没人管单子叫【物】。
软件里必须给它一个类,因为关系也要存数据(成绩、时间、状态)。
四、比喻的正确用法:用完就扔
比喻只负责把你送到门口,进门之后得按编程结构去理解。 2.7 会给出正式定义:面向对象是编程结构,不是现实世界的翻版。 判断方法很简单:这句话能不能用代码验证?能,就是结构;不能,就是比喻。
五、动手 Demo:原因之二:滥用比喻引起混乱
把常见的五条比喻逐条对照:书上的说法、软件里的实际、到底对不对得上。 再用一个【现实里找不到对应物】的类收尾。
class Student:
def __init__(self, name): self.name = name
class Course:
def __init__(self, title): self.title = title
class Enrollment: # 选课记录:现实里没有这个【物】
def __init__(self, student, course, score=None):
self.student = student
self.course = course
self.score = score
s = Student("小林")
c = Course("数据库")
e = Enrollment(s, c, 88)
print("这是学生吗", isinstance(e, Student))
print("这是课程吗", isinstance(e, Course))
print("它记的是", e.student.name, e.course.title, e.score)
实跑输出:
--------------------------------------------------------------------
原因之二——滥用比喻引起混乱
--------------------------------------------------------------------
讲面向对象最爱用现实世界打比方。**有些对得上,有些一对就歪:**
书上的比喻 软件里实际是什么 对得上吗
-----------------------------------------------------------
对象=现实中的物 内存里一块带类型的数据 大体对得上
类=分类 一份字段与方法的模板 对得上
继承=父子 把父类成员复制一份进来 常对不上
多态=变形 按对象的实际类型挑方法 完全不是
消息=说话 一次普通的函数调用 容易想歪
最要命的是第四行:**多态跟【变形】没有半点关系。**
它只是【同一句调用,落到不同实现上】。
还有个更隐蔽的坑——**现实世界里找不到对应物的类**:
class Student: ...
class Course: ...
class Enrollment: # 选课记录
def __init__(self, student, course, score=None):
self.student = student
self.course = course
self.score = score
问一句:`Enrollment` 在现实里是什么东西?**是一张选课单。**
它既不是学生也不是课程,**它是【两者之间的关系】。**
现实里没人管一张单子叫【东西】,可软件里必须给它一个类。
**这就是 2.6 要讲的【似是而非】:像,但不是。**
比喻只用来入门,进门之后要**扔掉比喻,按编程结构去理解**——
否则你会在【一个子类能不能有两个父亲】这类问题上卡住。
实测:Enrollment 既不是 Student 也不是 Course,两个 isinstance 都是 False。
它记的是两者之间的关系——现实里没有对应的【物】,软件里必须有个类。
30 秒实验
- 挑一条你用过的 OOP 比喻,试着找它的反例。
- 看看你的项目里有没有【关系类】,它们在现实里对应什么。
常见误区
- 把多态理解成【一个东西变成另一个东西】。它是【同一句调用落到不同实现】。
- 以为类必须都能在现实里找到对应物。关系本身也要成类。
自测三问(点开对答案)
1. 哪条比喻歪得最厉害? —— 【多态=变形】——多态跟变形无关,它只是同一句调用按对象实际类型落到不同实现。 2. 选课记录为什么必须单独成类? —— 它既不是学生也不是课程,而是两者之间的关系;关系本身也要存数据(成绩、时间、状态)。 3. 怎么判断一句话是结构还是比喻? —— 看能不能用代码验证:能验证的是结构,不能验证的是比喻。- ☐ 下一节(1.7 原因之三:面向对象的概念是抽象的)
相关笔记
- 原因之一:OOP结构复杂 — 上一条
- 原因之三:面向对象的概念是抽象的 — 下一条
- 以对象为中心编写软件的开发方法 — 结构视角看对象
- 🧩 面向对象是怎样工作的 · 索引