面向对象编程¶
英文: Object-Oriented Programming, OOP.
基础术语¶
在谈论具体的面向对象编程 (Object-Oriented Programming, OOP) 概念之前, 有必要先明确几个主要术语的含义.
数据指代类里的变量, 即成员变量. 代码指代类里的函数, 即成员函数/方法.
具体所使用的术语取决于所谈论的语言, 如下表所示:
| 所指 | 能指 | 语言 |
|---|---|---|
| 类的函数 | 方法 (Method) | Java, Rust |
| 成员函数 (Member function) | C++ | |
| 类的变量 | 字段 (Field) | Java, Rust |
| 成员变量 (Member variable) | C++ |
注: Rust 不属于传统 OOP 语言, 但其依然存在与传统 OOP 语言高度相似的概念.
此外, "内部" 一词一般指代类的内部, 即类的变量和函数.
三个特征¶
-
封装 (Encapsulation): 提高了类的易用性.
将数据 (字段) 与操作该数据的代码 (方法) 捆绑在一起 (放在一个类中).
同时利用可见性隐藏内部细节, 在保证数据合法性 (可以对内部数据的合法性做假设) 的同时降低代码耦合度 (外部无法依赖类内部的具体实现).- 提高内聚: 将数据 (字段) 与操作该数据的代码 (方法) 捆绑在一起 (放在同一个类中).
-
降低耦合: 利用可见性隐藏内部细节 (私有的字段/方法), 这样可以:
以一个
Image类为例, 其包含一个用于表示尺寸的字段dimensions. 一个有效Image的宽高不应该为 0 或负数:- 如果该字段公开, 外部代码可以任意篡改它, 导致其取值不可预测. 这会产生严重的副作用, 使得所有需要读取
dimensions字段的算法都必须兼容其特殊的取值范围 (增加复杂度), 或编写校验有效性的样本代码 (增加冗余度并降低效率). 比如面积函数不应该返回负数, 因此其实现不能是简单的宽乘以高. - 如果该字段私有, 外部代码无法篡改它, 换言之外部代码无法依赖该字段, 确保了低耦合. 对外仅提供只读的 getter 方法, 再通过良好的设计确保内部代码不可能将其设置为无效的值, 算法就可以直接假设该数据总是有效的. 比如, 将
dimensions作为私有字段, 并在构造时检测其初始值是否有效.
- 如果该字段公开, 外部代码可以任意篡改它, 导致其取值不可预测. 这会产生严重的副作用, 使得所有需要读取
-
继承 (Inheritance): 提高了代码的复用率.
子类可以通过继承复用父类的数据和代码, 但同时也会增加子类和父类之间的耦合度 (子类依赖父类).
-
多态 (Polymorphism): 提高了程序的可扩展性.
以
Circle和Rectangle类为例, 两个类均继承自Shape. 因此既可以单独使用这两个类, 也可以将他们当成一个Shape类使用.
比如这两种图形的面积计算公式不同, 但是都有面积. 因此只关心面积数据的代码可以将他们视作Shape(比如作为参数类型), 而无需在意其具体的形状.
不同编程语言实现三个特征的方式不同, 比如:
- C++ 和 Java 是基于类 (Class) 的面向对象.
- JavaScript 是基于原型 (Prototype) 的面向对象.
- Lua 是基于原表 (Meta Table) 的面向对象.
多态的含义是字面上的, 即多种形态 (many-shaped): 一个子类既可以作为子类使用, 也可以作为其父类使用.
优点¶
- 易于维护.
- 可重用性.
- 可扩展性.
缺点¶
- 不太适用于嵌入式开发.
- 性能略低于面向过程编程.
教学¶
以下说明几个教学中普遍存在的问题:
-
比喻滥用
使用生活中的经验与面向对象概念进行类比是一种常见的做法, 但部分例子虽然使用到了学生所熟悉的事务, 但却缺少和编程之间的联系.
从而使学生感到疑惑, 进而增加理解难度.
下面是此类不当比喻的常见例子:汽车类, 汽车有踩刹车和踩油门等操作, 具有颜色和重量等属性.
在现实世界中, 软件无法通过修改属性来改变车辆的颜色或重量. 若该车辆位于虚拟世界中, 这个比喻将合理许多.
面向对象是一种编程范式 (programming paradigm), 而严重脱离编程实际的类比对学生理解核心概念没有帮助.
-
术语滥用
面向对象存在较多的专业术语, 在讲解时应注意依赖关系. 确保由简到难, 由浅入深.
部分教师直接尝试使用高度抽象的描述和大量的专业术语来解释面向对象, 使学生一头雾水.不同领域同名术语可能具有不同的含义, 比如 C++ 的 "对象"1 和面向对象中的 "对象" 的定义是不同的.
-
边界模糊
部分概念并不属于面向对象. 比如 "万物皆对象", 这一概念只适用于部分面向对象的编程语言 (如 Java).
应该使学生认识到类只是实现面向对象的方法之一.
参见¶
- 面向对象是怎样工作的(第2版) ISBN: 978-7-115-54123-9.