# 面向对象问题求解

> CIE A-Level 计算机科学 · 9618
> 来源: https://www.owlsprep.com/zh/study/cie-9618-u13-object-oriented-problem-solving/

本模块讲解CIE 9618中面向对象（OO）问题求解的核心原则。你将学习如何通过识别类、对象、属性、方法来分解实际问题，并为系统实体之间的关系建立模型。

**先修:** [基础问题分解](https://www.owlsprep.com/zh/study/cie-9618-u13-problem-decomposition/); [基础编程概念](https://www.owlsprep.com/zh/study/cie-9618-u02-fundamental-programming/)

## 学习目标

- 使用核心面向对象原则分解实际问题
- 从自然语言问题描述中识别类、属性和方法
- 为类建立正确的关系模型（继承、聚合）
- 将封装原则应用于健壮的面向对象问题设计

## 用于问题分解的核心面向对象原则

面向对象问题求解围绕实体而非独立函数构建解决方案。这让大型复杂问题更易维护和扩展，因为系统某一部分的更改对其他部分的影响最小。

**面向对象问题求解** — 一种问题求解方法论，它围绕可复用实体（对象）构建解决方案，这些对象结合了数据（状态）和行为（方法），而非围绕独立函数或过程构建。

> **tip**
>
> 面向对象问题求解是编写代码前完成的设计步骤，它不仅仅是编程语言的一个特性。

**例题:** 使用面向对象原则分解一个简单的学校考勤系统，说出至少三个核心类。

1. 首先，列出系统需要跟踪的所有关键有形或概念实体。
2. 考勤系统的四个核心实体是：学生（Student）、教师（Teacher）、课程（Session）和考勤记录（AttendanceRecord）。
3. 为每个实体识别存储的数据（属性）和操作（方法）：
4. - **Student**: attributes = `studentID`, `name`, `yearGroup`; methods = `registerAttendance()`, `getDetails()`
- **Session**: attributes = `sessionID`, `date`, `room`; methods = `startSession()`, `endSession()`
- **AttendanceRecord**: attributes = `recordID`, `isPresent`; methods = `updateStatus()`
5. 每个实体对应一个类，特定的条目（例如学号12345）成为对应类的对象。

## 识别类、属性和方法

面向对象问题求解的第一个实践步骤是从自然语言问题描述中提取组件。一个简单的经验法则是：名词通常对应类或属性，动词通常对应方法。

> **mnemonic**
>
> 名词是类/属性，动词是方法！这个快速规则可以帮助你从任何问题描述中提取面向对象组件。

**例题:** 从以下描述中提取类、属性和方法：'一家咖啡店需要一个系统来跟踪订单。每个订单都有日期、商品列表和总价。订单可以计算税费并打印收据。'

1. 突出所有名词：咖啡店、系统、订单、日期、商品列表、总价、税费、收据。
2. 筛选出核心类：这里只有`Order`是顶层核心实体，其他名词都不是独立类。
3. 将剩余名词分配为`Order`类的属性：`date`、`itemList`、`totalPrice`。
4. 突出所有动词：跟踪、拥有、计算、打印。筛选出方法：`calculateTax()`和`printReceipt()`是`Order`的方法。

**概念自测**

测试你的理解：

1. 以下哪一项是`BankAccount`类的方法？

   - accountNumber
   - customerName
   - withdrawFunds
   - balance

   *答案:* withdrawFunds

   *解析:* 正确：`withdrawFunds`是BankAccount执行的操作（动词）。其他所有选项都是存储的数据（属性）。

## 为类之间的关系建立模型

识别出单个类之后，你需要为类之间的交互和关系建立模型。面向对象问题求解中最常用的关系是继承（is-a，是一个）、聚合（has-a，整体-部分）和关联。

**继承** — 一种'is-a（是一个）'关系，子类从超类继承属性和方法，支持代码复用和层次分类。

*例:* A `SavingsAccount` is a type of `BankAccount`, so `SavingsAccount` inherits from `BankAccount`.

**例题:** 为车辆租赁系统建立继承层次结构模型，该系统租赁汽车、摩托车和货车。所有车辆都有注册号、品牌和型号，并且可以被出租或归还。

1. 识别公共超类：所有实体都是车辆，因此创建顶层`Vehicle`类。
2. 将所有公共属性和方法移到超类中：`Vehicle`拥有属性`registrationNumber`、`make`、`model`，以及方法`hire()`、`returnVehicle()`。
3. 为每种特定车辆类型创建子类，添加任何唯一的属性或方法：
4. - `Car`: adds `numberOfSeats` attribute and `calculateInsuranceCost()` method
- `Motorbike`: adds `engineCapacity` attribute
- `Van`: adds `cargoCapacity` attribute
5. 这个层次结构避免了跨类重复代码，遵循了核心面向对象设计原则。

## 面向对象问题设计中的封装

封装是核心面向对象原则，支持健壮的问题设计。它隐藏了类的内部实现细节，只暴露受控的公共接口来与对象交互。

> **info**
>
> 封装阻止外部代码直接修改内部数据，减少意外错误，让设计更易维护。

**例题:** 将封装应用于`BankAccount`类，该类存储余额，只能通过批准的存款和取款修改。

1. 将`balance`属性设为私有，因此无法从`BankAccount`类外部直接访问或更改它。
2. 创建用于与余额交互的公共方法：`deposit(amount)`、`withdraw(amount)`和`getBalance()`来查看当前余额。
3. 在公共方法内部添加验证逻辑：`withdraw(amount)`可以拒绝金额超过当前余额的交易，防止出现负余额。
4. 外部代码只能通过批准的方法更改余额，因此类始终保持内部一致性。

## 常见错误

- **错误做法:** 将问题描述中的每个名词都拆分为独立的类。
  - 原因: 这会产生不必要的类，导致设计过于复杂，难以实现。
  - 正确做法: 将名词筛选为仅同时拥有属性和行为的核心实体；将琐碎名词合并为更大类的属性。
- **错误做法:** 对'has-a（整体-部分）'关系使用继承。
  - 原因: 例如，将`Wheel`设为`Car`的子类是错误的，因为轮胎不是汽车的一种。
  - 正确做法: 仅对'is-a（是一个）'关系使用继承，对'has-a（整体-部分）'关系使用聚合。
- **错误做法:** 将所有属性设为公共，破坏封装。
  - 原因: 这允许对内部对象状态进行不受控的修改，导致难以追踪的错误。
  - 正确做法: 默认将所有属性设为私有，仅暴露公共方法来实现与对象的受控交互。
- **错误做法:** 将所有功能放到一个大型主类中。
  - 原因: 这违反了单一职责原则，让设计难以测试、扩展和维护。
  - 正确做法: 将功能拆分到多个类中，每个类负责问题的一个特定部分。
- **错误做法:** 跳过面向对象设计，直接开始编写代码。
  - 原因: 这会导致混乱的临时设计，难以调试，也不符合考试评分标准。
  - 正确做法: 在为解决方案编写任何代码之前，始终先完成面向对象分解和类设计。

## 速查表

| 组件 | 识别方法 | 示例 |
| --- | --- | --- |
| 类 | 问题域中的核心名词/实体 | Order |
| 属性 | 名词，类的特性 | orderDate |
| 方法 | 动词，类执行的操作 | calculateTax() |
| 继承 | 'is-a（是一个）'层次关系 | SavingsAccount IS A BankAccount |
| 聚合 | 'has-a（整体-部分）'关系 | Order HAS Item objects |
| 封装 | 隐藏内部数据，暴露方法 | Private balance + public withdraw() |

## 下一步

掌握面向对象问题求解是设计所有大型软件系统的基础，也是CIE 9618试卷1中经常考核的主题。你在这里学习的原则将在你创建标准UML类图、为实践任务编写面向对象代码、为课程实践评估设计软件时应用。这种问题求解方法也直接适用于行业软件开发，因此它是A-Level考试之外的一项宝贵技能。接下来，你将在此核心知识的基础上，学习如何为面向对象系统关系建立模型，并在应试的可运行代码中实现面向对象概念。

- [陈述式问题求解](https://www.owlsprep.com/zh/study/cie-9618-u13-declarative-problem-solving/)
- [人工智能基础](https://www.owlsprep.com/zh/study/cie-9618-u13-artificial-intelligence-fundamentals/)
- [人工智能搜索技术](https://www.owlsprep.com/zh/study/cie-9618-u13-ai-search-techniques/)

---

来自 [OwlsPrep](https://www.owlsprep.com) —— A-Level / IB / AP / IGCSE 免费学习指南，依据官方考纲编写。原页面：https://www.owlsprep.com/zh/study/cie-9618-u13-object-oriented-problem-solving/
