前言
相比于第一次的电梯程序设计,我认为这一次的迭代作业并没有太多的算法要求,在逻辑等方面上更加清晰可观,没有冗杂和难解的算法逻辑问题,做起来并没有很困难,但此次作业逐步加深了对面向对象设计的理解,从简单的继承多态到复杂系统的类协作,每一次迭代都在优化代码结构和逻辑。但通过这三次作业,深入实践了面向对象设计中的继承、多态、容器类应用及复杂业务逻辑处理,进一步理解了单一职责、开闭原则、合成复用原则等设计思想的实际运用。题量属于正常,并没有很多,魔方问题和点线面问题再重构迭代程序问题较难,其他的题目相对容易。
知识点
- 继承与多态:通过抽象父类(如
Element、RubikCube、Goods)定义公共接口,子类(Point/Line/Plane、SquareCube/RegularPyramidCube、NormalGoods/ExpediteGoods)重写方法实现多态。
- 抽象类与接口:使用抽象类(如
Element、RubikCube)强制子类实现核心方法,体现 “模板方法” 模式。
- 封装:类属性私有化,通过构造方法和公共方法(
getter/setter)访问,如Customer、Flight类。
ArrayList的应用:在 “点线面容器类” 中使用ArrayList<Element>存储对象,实现动态增删(add()/remove())和遍历。
- 单一职责原则:每个类专注单一功能(如
Goods仅处理货物计算,Flight仅管理航班信息)。
- 开闭原则:通过继承和多态扩展功能(如新增货物类型时无需修改原有代码)。
- 合成复用原则:通过组合关系(如
Order包含Customer/Flight/Goods列表)实现协作,而非继承。
两次作业实现
题目集8
第一题(7-1 NCHU_点线面问题重构)
要求:在之前的点线面问题的基础上需对原有类进行重构,抽象出父类 Element,使 Point、Line、Plane 作为其子类,实现多态。重点在于合理设计抽象类的方法,确保子类正确重写。这一题比较基础,只是在之前的基础上进行重构,重点强调了继承和抽象方法。
设计
创建 Point、Line、Plane 对象,并通过 Element 引用调用 display() 方法,实现多态特性。
Point 类:
- 封装坐标属性
x、y,通过构造方法初始化,提供 getter/setter 方法。
display() 方法使用 printf 格式化输出坐标,保留两位小数,符合格式要求。
Line 类:
- 包含两个
Point 对象和颜色属性,通过构造方法关联起点、终点和颜色。
display() 方法依次输出颜色、起点 / 终点坐标及线段长度,长度计算使用勾股定理,结果保留两位小数。
Plane 类:
- 仅包含颜色属性,
display() 方法直接输出颜色,格式正确。
第二题(7-2 NCHU_雨刷程序功能扩展设计)
要求:该题目要求对汽车雨刷程序进行重构,使其支持两种不同的雨刷系统(表 1 和表 2),并能够通过扩展策略实现功能新增。题目难度偏容易,运用了类的封装、继承、多态、抽象类、接口。分别为表一和表二来增添和设计接口。
设计
定义WiperSystem接口封装雨刷系统的核心逻辑(档位名称、速度计算、档位 / 刻度范围等),通过Table1WiperSystem和Table2WiperSystem实现具体策略
主程序根据输入的系统类型(1 或 2)动态选择策略实现类,解耦了不同系统的差异,新增系统时只需扩展WiperSystem接口,无需修改现有代码。
Lever与Dial类:
封装控制杆和刻度盘的操作逻辑,通过WiperSystem接口校验操作合法性(如档位是否可升降),避免硬编码范围,符合单一职责原则
Agent类:
作为代理协调各组件,处理操作指令、更新雨刷速度并输出状态,隔离了高层模块与具体策略的直接依赖,符合依赖倒转原则。
抽象类复用
AbstractWiperSystem:
提供默认的合法性校验实现(canLeverUp/canDialUp等),减少子类重复代码,遵循模板方法模式。
第三题(7-3 NCHU_航空货运管理系统)(重点)
该题目要求设计一个航空货运管理系统,涉及客户、货物、航班和订单等多个类的设计,以及它们之间的交互和业务逻辑处理。主要考查面向对象编程中的类设计、封装、继承、多态以及业务逻辑实现和输入输出处理等方面的能力。需要设计合理的类结构,正确实现业务逻辑,处理输入输出格式,并进行必要的异常处理。题目本身难度并不高,按要求设计类,正确处理业务逻辑,完成正确的输入输出的内容便可完成。
设计
核心结构(类)
Customer:仅封装客户基础信息(编号、姓名、电话、地址)。
Goods:专注货物相关计算(体积重量、计费重量、费率、运费)。
Flight:仅管理航班基础信息(航班号、载重等)。
Order:处理订单逻辑(总重量计算、超载检查、信息整合)。
核心方法:
-
calculateVolumeWeight():计算体积重量(长 × 宽 × 高 ÷6000)。
getChargeableWeight():取实际重量与体积重量的较大值。
getRate():根据计费重量返回费率(硬编码普通货物费率表)。
calculateFreight():计算单货物运费(计费重量 × 费率)。
具体设计可参考类图:
SourceMonitor分析
![]()
从报表数据可看出以下信息
- 代码规模:248 行代码,162 条语句,类数量 5 个,方法平均复杂度低(5.79 条语句 / 方法),整体规模适中,适合维护。
- 注释率:6.9% 偏低,关键逻辑(如费率计算规则)缺乏注释,需补充以增强可读性。
- 分支语句占比:5.6%,条件逻辑较少,代码流程线性,利于理解。
- 最大深度 5:主要集中在
main方法的输入处理和业务逻辑嵌套,建议拆分为独立方法(如readCustomer()、readGoods()等),降低嵌套深度。
- 方法复杂度:
main方法作为最复杂方法(行号 57),承担过多职责,需按功能模块拆分(输入、处理、输出),提升可维护性。
题目集九
第一题(7-1 NCHU_魔方问题)
核心需求:实现正方体和正三棱锥魔方的类设计,计算并输出颜色、表面积、体积,体现继承与多态。
类设计与继承关系
-
抽象类 Solid:
定义立体图形的公共属性(单元边长 side)和抽象方法(表面积、体积计算),作为 Cube(正方体)和 RegularPyramid(正四面体,原代码误写为正三棱锥,需修正为正四面体,4 个等边三角形面)的基类。
-
子类 Cube:
正确实现正方体的表面积(6a2)和体积(a3)计算。
-
子类 RegularPyramid(修正为正四面体):
- 表面积:4 个等边三角形面,公式为 4×43a2=3a2。
- 体积:正四面体体积公式 122a3,正确。
-
抽象类 RubikCube:
封装魔方的公共属性(颜色、阶数、单元立体图形),定义抽象方法供子类实现魔方的整体计算(边长 = 阶数 × 单元边长)。
-
子类 SquareCube(正方体魔方):
- 表面积:6(layer×side)2(通过
Cube.getArea() \times layer^2 实现,逻辑正确,因 Cube.getArea() 是 6side2,乘以 layer2 即 6(layer×side)2)。
- 体积:(layer×side)3(通过
Cube.getVolume() \times layer^3 实现,正确)。
-
子类 RegularPyramidCube(正四面体魔方):
- 表面积:3(layer×side)2(通过
RegularPyramid.getArea() \times layer^2 实现,修正后单元表面积为 3side2,乘以 layer2 即 3(layer×side)2,正确)。
- 体积:122(layer×side)3(通过
RegularPyramid.getVolume() \times layer^3 实现,正确)。
- 主方法:
按题目要求读取两部分输入,创建魔方对象,通过多态 display 方法输出,动态调用子类的 getArea() 和 getVolume(),体现继承与多态特性。
display 方法:
格式化输出颜色、表面积(保留两位小数)、体积(保留两位小数),符合题目格式要求。
第二题(7-2 NCHU_点线面问题再重构)
核心需求:该题是题目集8中点线面问题的迭代程序设计,从容器类方面着手,扩展点线面系统,重点考查面向对象设计中的多态、集合操作和用户交互处理,要求严格遵循类结构和输入输出格式,提升代码的可维护性和健壮性。通过合理设计类层次和容器方法,可有效实现动态图形管理和多态输出。
- 抽象类
Element:
- 作为所有图形元素(点、线、面)的基类,定义了抽象方法
display(),这是一个良好的设计,符合面向对象编程中抽象类的使用场景,通过抽象方法强制子类实现自己的显示逻辑,从而实现多态性。
- 子类
Point、Line 和 Plane:
Point 类:
- 封装了点的坐标
x 和 y,并提供了相应的访问器(getX() 和 getY())和修改器(setX() 和 setY())方法,符合封装的原则。
display() 方法实现了按照指定格式输出点的坐标,即 (x.xx, y.yy),保留两位小数,格式正确。
Line 类:
- 包含两个
Point 对象(point1 和 point2)以及一个颜色属性 color,通过组合的方式表示线的起点、终点和颜色,这种设计合理。
display() 方法详细地输出了线的颜色、起点坐标、终点坐标以及长度。长度的计算通过勾股定理实现,即 Math.sqrt(dx * dx + dy * dy),其中 dx 和 dy 分别是终点和起点坐标的差值,并且结果保留两位小数,计算和输出格式都正确。
Plane 类:
- 封装了面的颜色属性
color,并提供了访问器和修改器方法。
display() 方法简单地输出面的颜色,符合面的显示逻辑。
- 属性
list:
- 使用
ArrayList<Element> 来存储所有的图形元素,这是一个合适的选择,因为 ArrayList 提供了动态数组的功能,方便进行元素的添加和删除操作。
- 方法
add(Element element):
- 该方法用于向容器中添加元素,实现简单直接,调用了
ArrayList 的 add() 方法,将元素添加到列表中。
- 方法
remove(int index):
- 用于从容器中删除指定索引位置的元素。在删除之前,先检查索引的合法性,即
index >= 0 && index < list.size(),只有在索引合法的情况下才进行删除操作,作为一种边界检查,能够防止程序因非法索引而崩溃。
- 方法
getList():
- 返回存储图形元素的
ArrayList,这在需要对容器中的元素进行遍历或其他操作时非常有用。
第三题(7-3 NCHU_航空货运管理系统)(重点)
该题在题目集8的航空货运管理系统的基础上增加了多类型扩展需求,考验面向对象设计的高级特性(继承、多态、设计模式),更注重了代码的可扩展性和可维护性,实现多态计费、客户折扣、支付方式
处理,由单一货物类型、固定折扣转变为多货物类型、多客户类型、多支付方式,设计重点也从封装与流程实现到多态、继承、设计模式(策略 / 工厂)。做这道题的时候,时间相对花的也更多了,但也学会了一些继承与多态的知识,总之受益匪浅。
设计
-
客户类(Customer)
- 职责:封装客户编号、姓名、电话、地址,提供姓名和电话的访问方法。
-
货物类(Goods)
- 核心功能
- 计算体积重量(长 × 宽 × 高 ÷6000)、计费重量(取实际重量与体积重量较大值)。
- 费率计算:根据计费重量分档(<20kg→35 元,20-50kg→30 元,50-100kg→25 元,≥100kg→15 元)。
- 应交运费 = 计费重量 × 费率。
-
航班类(Flight)
- 职责:存储航班号、起降机场、日期、最大载重量,提供航班号和最大载重的访问方法。
-
订单类(Order)
- 核心功能:
- 计算订单总重量(所有货物计费重量之和)。
- 检查载重是否超限(
isOverload())。
- 协调各组件输出订单信息和货物明细。
设计类图如下:
![]()
SourceMonitor分析
![]()
踩坑心得
-
我做航空货运管理系统时输入顺序没有保持严格性:未按客户→货物→航班→订单顺序读取,容易数据错位。可能也是当时未添加适当的注释(做题时确实要避免偷懒,不能省掉一些看似无用的东西)来明确每一步输入内容,容易造成逻辑混乱的问题,
-
货物数量n需循环n次,确保for循环索引正确(从 0 开始),避免少读 / 多读。在处理业务逻辑时计费重量的计算中单位的换算一开始粗心,并没有察觉,费率分档逻辑条件判断需从小到大(<20→<50→<100→else),避免区间覆盖错误(如 50kg 误判为≥100kg
- 做雨刷系统时我初期对
WiperSystem接口的方法职责(如getLeverName、calculateSpeed)理解不足,导致子类实现错误。
- 做魔方题目时
RubikCube子类未正确计算魔方边长(阶数 × 单元边长),导致尺寸错误(如layer*side写成layer+side)。
改进建议
1.增强输入验证:加非负数值、日期格式校验,处理NumberFormatException,提升代码的健壮性。
2.封装业务逻辑:将总支付金额计算移至Order类,减少Main职责,提升内聚性。
3.规范代码注释:多添加公式注释,优化变量命名(如goodsCount→numGoods),提升可读性。
4.对于继承和动态以及接口了解不够,运用不娴熟,得加强该方面知识。
总结
通过这次题目集,使我更加深入理解了面向对象编程核心思想,掌握了策略模式等设计模式,提升了复杂逻辑处理能力,了解单一职责、开闭原则、多态与继承等方面的知识,发现了自身的一些不足,(如对于一些代码的注释并没有写清)。还是要实践出真知,多通过代码实现,深刻理解设计原则和模式的实际应用,而非停留在理论。
同时细节决定成败,在输入输出的精度、边界条件处理上,直接影响程序正确性,需要反复的校验。对自己代码要进行持续优化:代码需不断重构,通过设计模式和结构优化,提升可维护性与扩展性,适应需求变化。多向老师和同学交流,多学习,提升自身硬实力是最重要的。