💻 第七章 成为会使用面向对象编程的程序员吧
📄 一句话概括

拿到一个类有三招——拿来就用(调方法)、装进去用(组合 has-a)、继承着用(is-a);三招覆盖绝大多数设计。

📝 本节和前面几节的关系

图纸与成品分清了,最后一问:拿到一个类,能拿它干什么?答案恰好三种。

一、用法 1:拿来就用

把类当工具箱:直接调它的方法或常量,如数学工具、日期格式化——MathBox.round2(x) 用完即走。 特点是无状态、零负担:不建对象或建了随手扔,适合【纯功能】的场景。 各类语言的工具类库(Java 的 Math、Python 的 math 模块函数)都是这一路的产物。

二、用法 2:装进去用(组合)

一个类的字段里装另一个类的对象——Car 里装一台 Engine,关系是【有】(has-a)。 这正是 7.3 拼装观的正式机制:组件拼大件,用的就是组合。 组合的好处:Engine 可以单独开发、单独升级、单独测试——Car 毫无察觉。

三、用法 3:继承着用

子类继承父类再扩展——SportsCar 是一种 Car(is-a),白得 start() 再加 turbo()。 适合【真的是一种】的场景:概念上确实存在家族关系,且子类要沿袭父类的接口合同。 【⚠️ 2026 现状】三招的使用心法:默认优先组合(招 2),确有 is-a 关系才用招 3——再次呼应【组合优于继承】的警语。

四、动手 Demo:类的三种使用方法

三招各演一遍:工具箱拿来就用、组合装引擎、继承造跑车。

class MathBox:
    PI = 3.14
    @staticmethod
    def round2(x): return round(x, 2)
class Engine:
    def start(self): return "引擎发动"
class Car:
    def __init__(self): self.engine = Engine()
class SportsCar(Car):
    def turbo(self): return "涡轮! " + self.engine.start()
print(MathBox.round2(3.14159))
print(Car().engine.start())
print(SportsCar().turbo())

实跑输出:

--------------------------------------------------------------------
类有三种使用方法
--------------------------------------------------------------------

拿到一个类, 有三招可用:

    招式1 拿来就用: MathBox.round2(3.14159) = 3.14
    招式2 装进去用: car.engine.start() -> 引擎发动
    招式3 继承着用: sc.turbo() -> 涡轮加速! 引擎发动

  招式         关系           关键词     例子
  ---------------------------------------------------------
  拿来就用     调用方法       工具       Math/日期工具类
  装进去用     有 (has-a)     组合       Car 装一台 Engine
  继承着用     是 (is-a)      继承       SportsCar 是 Car

三招覆盖绝大多数设计: 无状态用招 1, 整体-部分用招 2,
真的【是一种】才用招 3——和 7.9 的警语【组合优于继承】接上了。

SportsCar 既用了招 3(继承 Car)又用了招 2(引擎装在车里)——三招可以叠着用。 判断用哪招就问一句:是工具(招 1)?有它(招 2)?是它(招 3)?

30 秒实验

  1. 给你的项目里的两个类判断关系:该用组合还是继承?说出理由。
  2. 把 7.3 的 Car 改成用继承实现,再对比两种写法的耦合程度。

常见误区

  1. 以为继承是【用类】的头等方式——多数场景组合更灵活,继承只留给真 is-a。
  2. 以为三种用法互斥——一个类常常同时被组合、被继承,招式可叠加。
自测三问(点开对答案) 1. 类的三种使用方法? —— 拿来就用(工具)、装进去用(组合 has-a)、继承着用(is-a)。 2. 7.3 拼装观对应哪一招? —— 招 2 组合——组件装进大件。 3. 默认优先哪一招?为什么? —— 组合——耦合更低、更易替换,呼应组合优于继承。

相关笔记