🧩 第一章 面向对象:让软件开发变轻松的技术
📄 一句话概括

拿现实世界打比方能入门,但最好的一条比喻也只对一半——多态跟【变形】没有半点关系,选课记录在现实里根本不是一个【物】。

📝 本节和前面几节的关系

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 秒实验

  1. 挑一条你用过的 OOP 比喻,试着找它的反例。
  2. 看看你的项目里有没有【关系类】,它们在现实里对应什么。

常见误区

  1. 把多态理解成【一个东西变成另一个东西】。它是【同一句调用落到不同实现】。
  2. 以为类必须都能在现实里找到对应物。关系本身也要成类。
自测三问(点开对答案) 1. 哪条比喻歪得最厉害? —— 【多态=变形】——多态跟变形无关,它只是同一句调用按对象实际类型落到不同实现。 2. 选课记录为什么必须单独成类? —— 它既不是学生也不是课程,而是两者之间的关系;关系本身也要存数据(成绩、时间、状态)。 3. 怎么判断一句话是结构还是比喻? —— 看能不能用代码验证:能验证的是结构,不能验证的是比喻。

相关笔记