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

一个【五脏俱全】的类要交代八件事,15 行代码只做一件事;难的不是背关键字,是不知道该用哪几个。

📝 本节和前面几节的关系

1.4 列了三条原因,这一节讲第一条:语言里的构造到底多在哪。

一、一个最小的完整类

下面这个类只干一件事——把数字乘 2。但它把 OOP 的结构要素全占了。 15 行、5 个方法、3 个数据成员。 对比一下:过程式写这件事,一行 def double(n): return n * 2 就完了。 多出来的不是废话——每一行都在交代一件 C 语言里没有的事。

二、八件事分别是什么

一、类名;二、继承自谁(class Base(abc.ABC))。 三、类变量(count = 0,所有实例共享);四、构造(__init__)。 五、实例变量(self._n,下划线是约定私有);六、属性访问器(@property)。 七、抽象方法(@abc.abstractmethod,子类必须实现);八、覆写(子类重写 work)。 八件事少交代一件,类的语义就不完整。

三、各语言的构造数量

Java 要记 class、interface、extends、implements、abstract、final 等等——十来个关键字。 C++ 还有 public/private/protected/virtual/template——同样是十来个。 Python 没有这么多关键字,但有一堆双下划线约定(__init__、__str__、__eq__…),学习成本换了形式而已。 所以【换一门语言】并不能绕开这件事。

四、难在取舍,不在记忆

背下这些关键字,一天够了。难的是【这个需求该写几个类】。 同一个需求,写三个类能过,写八个类也能过——区别在三年后谁改得动。 这就是 1.1 说的:语法只是第一层,设计是第二层。 第 10 章会正面回答【该写几个类】——答案是拟人化和职责分配。

五、动手 Demo:原因之一:OOP结构复杂

一个最小但完整的类,把 OOP 的结构要素全用上,数一数它要交代几件事。 再列一列主流语言各自要你记住的类相关关键字。

import abc

class Base(abc.ABC):          # 1 类名  2 继承自谁
    count = 0                 # 3 类变量
    def __init__(self, n):    # 4 构造
        self._n = n           # 5 实例变量
        Base.count += 1
    @property
    def n(self):              # 6 属性访问器
        return self._n
    @abc.abstractmethod
    def work(self): ...       # 7 抽象方法

class Impl(Base):
    def work(self):           # 8 覆写
        return self.n * 2

print("方法数", len([1 for k in dir(Base) if not k.startswith('__')]))
print("结果  ", Impl(21).work())

实跑输出:

--------------------------------------------------------------------
原因之一——OOP 结构复杂
--------------------------------------------------------------------

  一个【五脏俱全】的类,要交代八件事。逐条对上代码:

      import abc
      class Base(abc.ABC):              # 1 类名   2 继承自谁
          count = 0                     # 3 类变量
          def __init__(self, n):        # 4 构造
              self._n = n               # 5 实例变量(下划线=约定私有)
              Base.count += 1
          @property
          def n(self):                  # 6 属性访问器
              return self._n
          @abc.abstractmethod
          def work(self): ...           # 7 抽象方法(子类必须实现)
      class Impl(Base):
          def work(self):               # 8 覆写
              return self.n * 2

  实测这份最小但完整的类:**15 行代码、5 个方法、3 个数据成员**。
  而它只做一件事——把数字乘 2。

  再看主流语言各自要你记住的【OOP 构造】有多少:

  语言           类相关关键字                              数量级
  ----------------------------------------------------------------
  Java           class interface extends implements        十来个
  C++            class public private virtual template     十来个
  Python         class 加 __init__ 等双下划线约定          靠约定
  JavaScript     class extends super(早期靠原型)         少

  **难点不在【背不下来】,在【不知道该用哪几个】。**
  同一个需求,写三个类能过,写八个类也能过,**区别在三年后谁改得动。**
  这就是 1.1 说的:语法只是第一层,设计是第二层。

实测:这个类 15 行,做的是【乘 2】——过程式一行就够。 多出来的每一行都在交代 C 里没有的概念:谁能看、谁继承谁、子类必须实现哪个。

30 秒实验

  1. 把你常用的一个类拿出来,标一标它用到了这八件事里的哪几件。
  2. 试着用过程式改写它,看会丢掉哪些约束。

常见误区

  1. 以为结构复杂是【语法丑】。复杂是因为要表达的东西多了。
  2. 以为 Python 简单就没这问题。关键字少了,约定多了。
自测三问(点开对答案) 1. 一个完整的类通常要交代哪八件事? —— 类名、继承自谁、类变量、构造、实例变量、属性访问器、抽象方法、覆写。 2. 为什么说难点不在背关键字? —— 背下来只要一天,难的是判断这个需求该写几个类、每个类该负责什么。 3. Python 的类相关关键字少,是不是就简单? —— 不是,成本换成了双下划线约定(__init__、__str__、__eq__ 等),一样要学。

相关笔记