面向对象问题求解
CIE A-Level 计算机科学· 第13单元:计算思维与问题求解,主题4· 20 分钟阅读
1. 用于问题分解的核心面向对象原则★★☆☆☆⏱ 5 min
面向对象问题求解围绕实体而非独立函数构建解决方案。这让大型复杂问题更易维护和扩展,因为系统某一部分的更改对其他部分的影响最小。
面向对象问题求解
一种问题求解方法论,它围绕可复用实体(对象)构建解决方案,这些对象结合了数据(状态)和行为(方法),而非围绕独立函数或过程构建。
使用面向对象原则分解一个简单的学校考勤系统,说出至少三个核心类。
- 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()
- Student: attributes =
- 5
每个实体对应一个类,特定的条目(例如学号12345)成为对应类的对象。
2. 识别类、属性和方法★★☆☆☆⏱ 6 min
面向对象问题求解的第一个实践步骤是从自然语言问题描述中提取组件。一个简单的经验法则是:名词通常对应类或属性,动词通常对应方法。
从以下描述中提取类、属性和方法:'一家咖啡店需要一个系统来跟踪订单。每个订单都有日期、商品列表和总价。订单可以计算税费并打印收据。'
- 1
突出所有名词:咖啡店、系统、订单、日期、商品列表、总价、税费、收据。
- 2
筛选出核心类:这里只有
Order是顶层核心实体,其他名词都不是独立类。 - 3
将剩余名词分配为
Order类的属性:date、itemList、totalPrice。 - 4
突出所有动词:跟踪、拥有、计算、打印。筛选出方法:
calculateTax()和printReceipt()是Order的方法。
测试你的理解:
以下哪一项是
BankAccount类的方法?accountNumber
customerName
withdrawFunds
balance
显示答案
2 —正确:
withdrawFunds是BankAccount执行的操作(动词)。其他所有选项都是存储的数据(属性)。
3. 为类之间的关系建立模型★★★☆☆⏱ 7 min
识别出单个类之后,你需要为类之间的交互和关系建立模型。面向对象问题求解中最常用的关系是继承(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: addsnumberOfSeatsattribute andcalculateInsuranceCost()methodMotorbike: addsengineCapacityattributeVan: addscargoCapacityattribute
- 5
这个层次结构避免了跨类重复代码,遵循了核心面向对象设计原则。
4. 面向对象问题设计中的封装★★★☆☆⏱ 6 min
封装是核心面向对象原则,支持健壮的问题设计。它隐藏了类的内部实现细节,只暴露受控的公共接口来与对象交互。
将封装应用于BankAccount类,该类存储余额,只能通过批准的存款和取款修改。
- 1
将
balance属性设为私有,因此无法从BankAccount类外部直接访问或更改它。 - 2
创建用于与余额交互的公共方法:
deposit(amount)、withdraw(amount)和getBalance()来查看当前余额。 - 3
在公共方法内部添加验证逻辑:
withdraw(amount)可以拒绝金额超过当前余额的交易,防止出现负余额。 - 4
外部代码只能通过批准的方法更改余额,因此类始终保持内部一致性。
5. 常见陷阱
错误做法:
将问题描述中的每个名词都拆分为独立的类。
原因:
这会产生不必要的类,导致设计过于复杂,难以实现。
正确做法:
将名词筛选为仅同时拥有属性和行为的核心实体;将琐碎名词合并为更大类的属性。
错误做法:
对'has-a(整体-部分)'关系使用继承。
原因:
例如,将Wheel设为Car的子类是错误的,因为轮胎不是汽车的一种。
正确做法:
仅对'is-a(是一个)'关系使用继承,对'has-a(整体-部分)'关系使用聚合。
错误做法:
将所有属性设为公共,破坏封装。
原因:
这允许对内部对象状态进行不受控的修改,导致难以追踪的错误。
正确做法:
默认将所有属性设为私有,仅暴露公共方法来实现与对象的受控交互。
错误做法:
将所有功能放到一个大型主类中。
原因:
这违反了单一职责原则,让设计难以测试、扩展和维护。
正确做法:
将功能拆分到多个类中,每个类负责问题的一个特定部分。
错误做法:
跳过面向对象设计,直接开始编写代码。
原因:
这会导致混乱的临时设计,难以调试,也不符合考试评分标准。
正确做法:
在为解决方案编写任何代码之前,始终先完成面向对象分解和类设计。
6. 速查表
组件 | 识别方法 | 示例 |
|---|---|---|
类 | 问题域中的核心名词/实体 | Order |
属性 | 名词,类的特性 | orderDate |
方法 | 动词,类执行的操作 | calculateTax() |
继承 | 'is-a(是一个)'层次关系 | SavingsAccount IS A BankAccount |
聚合 | 'has-a(整体-部分)'关系 | Order HAS Item objects |
封装 | 隐藏内部数据,暴露方法 | Private balance + public withdraw() |
真题中的出现
AI 根据考纲规律估算的考点位置,请对照官方真题核实准确性。仅作复习重点参考。
- 2022 · 12
识别图书馆系统的面向对象组件
- 2023 · 11
使用面向对象原则分解动物园系统
- 2024 · 13
为在线商城建立面向对象结构模型
深入阅读
下一步
掌握面向对象问题求解是设计所有大型软件系统的基础,也是CIE 9618试卷1中经常考核的主题。你在这里学习的原则将在你创建标准UML类图、为实践任务编写面向对象代码、为课程实践评估设计软件时应用。这种问题求解方法也直接适用于行业软件开发,因此它是A-Level考试之外的一项宝贵技能。接下来,你将在此核心知识的基础上,学习如何为面向对象系统关系建立模型,并在应试的可运行代码中实现面向对象概念。
