面向对象程序设计作业1-3总结
前言
OOP作业的1-3结束了,1-3,以航空货运配载为真实业务场景,不断增加新的功能,我学到了很多:
1.熟悉了Java基本语法;
2.初步建立起了面向对象的设计思路;
3.认识到了代码可拓展性的重要;
4.学会了基础的项目分析与代码编写能力
Complexity Metrics(复杂度分析)
因为下面要用到复杂度分析,所以先在此给出一些相关概念。
我们需要使用的主要是方法和类的复杂度分析。
方法的复杂度分析主要基于循环复杂度的计算。循环复杂度是一种表示程序复杂度的软件度量,由程序流程图中的“基础路径”数量得来。
1.ev(G):即Essentail Complexity,用来表示一个方法的结构化程度,范围在[1,v(G)]之间,值越大则程序的结构越“病态”,其计算过程和图的“缩点”有关。
2.iv(G):即Design Complexity,用来表示一个方法和他所调用的其他方法的紧密程度,范围也在[1,v(G)]之间,值越大联系越紧密。
3.v(G):即循环复杂度,可以理解为穷尽程序流程每一条路径所需要的试验次数。
对于类,有OCavg和WMC两个项目,分别代表类的方法的平均循环复杂度和总循环复杂度。
下面我将从程序结构及bug分析两个方面来总结我OOP作业的三次作业。
第一次作业
作业要求
设计一个基础的航班货运配载模块。系统需要记录航班的基本信息(航班号、最大起飞重量、最大业载重量)。地勤人员可以按照货物重量从高到低向该航班添加货物(货物名称、重量)。系统需要实时计算当前已装载的总重量,并判断是否超载。类设计必须符合单一职责原则(SRP)。
实现方式
第1行:输入航班号flightNo(字符串,例如CA1201)
第2行:输入该航班最大载重重量maxWeight(实型数,例如1200.0)
第3行:输入该航班要装载的货物件数n(整型数,例如10)
从第4行开始,循环输入要装载的货物的名称cargoName(字符串)和cargoWeight重量(实型数)
代码规模
第一次作业代码规模如下图。
| 源文件 | 总行数 | 代码行数 | 代码占比 | 注释行数 | 注释占比 | 空行数 | 空行占比 |
|---|---|---|---|---|---|---|---|
| Cargo.java | 15 | 13 | 87% | 0 | 0% | 2 | 13% |
| Flight.java | 14 | 12 | 86% | 0 | 0% | 2 | 14% |
| LoadManifest.java | 23 | 20 | 87% | 0 | 0% | 3 | 13% |
| CargoSorter.java | 24 | 21 | 88% | 0 | 0% | 3 | 12% |
| Main.java | 13 | 11 | 85% | 0 | 0% | 2 | 15% |
| 总计 | 89 | 77 | 87% | 0 | 0% | 12 | 13% |
类图
第一次作业类图如下,其中Main是主类

复杂度分析
第一次作业的复杂度分析如下
| 方法 | ev(G) | iv(G) | v(G) |
|---|---|---|---|
| Main.main(String[]) | 1 | 2 | 2 |
| Cargo.Cargo(String, double) | 1 | 1 | 1 |
| Cargo.getCargoName() | 1 | 1 | 1 |
| Cargo.getCargoWeight() | 1 | 1 | 1 |
| Cargo.setManifest(LoadManifest) | 1 | 1 | 1 |
| Flight.Flight(String, double) | 1 | 1 | 1 |
| Flight.getFlightNo() | 1 | 1 | 1 |
| Flight.getMaxLoadWeight() | 1 | 1 | 1 |
| Flight.setManifest(LoadManifest) | 1 | 1 | 1 |
| LoadManifest.LoadManifest(Flight) | 1 | 1 | 1 |
| LoadManifest.getTotalWeight() | 1 | 2 | 2 |
| LoadManifest.addCargo(Cargo) | 1 | 1 | 1 |
| LoadManifest.isOverload() | 1 | 2 | 2 |
| LoadManifest.getCargoList() | 1 | 1 | 1 |
| LoadManifest.getFlight() | 1 | 1 | 1 |
| CargoSorter.CargoSorter(LoadManifest) | 1 | 1 | 1 |
| CargoSorter.sortCargo() | 1 | 4 | 4 |
| CargoSorter.print() | 1 | 4 | 4 |
| Total | 19 | 28 | 28 |
| Average | 1.06 | 1.56 | 1.56 |
可以看出最复杂的是CargoSorter.sortCargo和print方法
1.双层循环结构(选择排序算法)
2.条件比较(判断货物重量大小)
3.数据交换逻辑
4.是整个项目逻辑最复杂、控制流最多的方法
Bug分析
在超载测试测试点出现bug,后发现输出格式有误
第二次作业
作业要求
1.航班信息管理:记录航班号、最大起飞重量、最大业载重量。
2.货舱管理:
每个货舱有唯一标识(如“前舱”)、最大载重、行数、列数(组成位置网格)。
货舱与其位置是组合关系(CargoCompartment 创建时内部生成 Position 列表)。
货舱与装载的货物是聚合关系(Cargo 可独立存在)。
3.货物装载:
输入所有待装载货物(名称、重量、目标货舱ID)。
系统先按货物重量从高到低排序,再依次尝试将货物装入指定的货舱。
如果目标货舱的当前重量 + 该货物重量 ≤ 该货舱最大载重,则装载成功,否则装载失败并给出提示。
4.输出要求:
按排序后的顺序输出每件货物的装载结果(成功或失败)。
输出每个货舱的已装载总重量及状态(是否超载)。
输出航班整体总重量及与最大起飞重量、最大业载重量的对比,判断整体是否超载。
实现方式
第1行:航班号(字符串)
第2行:最大起飞重量(实型)
第3行:最大业载重量(实型)
第4行:货舱数量 m(整数,1 ≤ m ≤ 5)
接下来 m 行,每行描述一个货舱:货舱ID(字符串) 最大载重(实型) 行数(整数) 列数(整数)
接下来一行:货物件数 n(整数,1 ≤ n ≤ 100)
接下来 n 行,每行描述一件货物:货物名称(字符串) 重量(实型) 目标货舱ID(字符串,必须与上面输入的某个货舱ID一致)。
例如:
CA1201
20000
15000
2
前舱 5000 2 5
后舱 8000 3 5
3
电子产品 850 前舱
水果 500 后舱
体育用品 128 前舱
代码规模
第二次作业代码规模如下图
| 源文件 | 总行数 | 代码行数 | 代码占比 | 注释行数 | 注释占比 | 空行数 | 空行占比 |
|---|---|---|---|---|---|---|---|
| Position.java | 12 | 9 | 75% | 1 | 8% | 2 | 17% |
| Cargo.java | 14 | 10 | 71% | 1 | 7% | 3 | 21% |
| CargoCompartment.java | 37 | 31 | 84% | 1 | 3% | 5 | 14% |
| Flight.java | 31 | 26 | 84% | 1 | 3% | 4 | 13% |
| LoadDispatcher.java | 15 | 13 | 87% | 1 | 7% | 1 | 7% |
| InputValidator.java | 9 | 7 | 78% | 1 | 11% | 1 | 11% |
| Main.java | 68 | 59 | 87% | 1 | 1% | 8 | 12% |
| 总计 | 186 | 155 | 83% | 7 | 4% | 24 | 13% |
类图
第二次作业类图如下,其中Main是主类

复杂度分析
第二次作业的复杂度分析如下。
| 方法 | ev(G) | iv(G) | v(G) |
|---|---|---|---|
| Position.Position(int, int) | 1 | 1 | 1 |
| Position.getPosName() | 1 | 1 | 1 |
| Cargo.Cargo(String, double) | 1 | 1 | 1 |
| Cargo.getId() | 1 | 1 | 1 |
| Cargo.getWeight() | 1 | 1 | 1 |
| CargoCompartment.CargoCompartment(String, double, int, int) | 1 | 2 | 2 |
| CargoCompartment.addCargo(Cargo) | 1 | 2 | 2 |
| CargoCompartment.getCurrentWeight() | 1 | 1 | 1 |
| CargoCompartment.getId() | 1 | 1 | 1 |
| CargoCompartment.getMaxWeight() | 1 | 1 | 1 |
| CargoCompartment.isOverweight() | 1 | 2 | 2 |
| CargoCompartment.getCargos() | 1 | 1 | 1 |
| Flight.Flight(String, double, double) | 1 | 1 | 1 |
| Flight.addCompartment(CargoCompartment) | 1 | 1 | 1 |
| Flight.getCompartmentById(String) | 1 | 3 | 3 |
| Flight.getTotalCargoWeight() | 1 | 2 | 2 |
| Flight.getCompartments() | 1 | 1 | 1 |
| Flight.getMaxTakeoffWeight() | 1 | 1 | 1 |
| Flight.getMaxPayloadWeight() | 1 | 1 | 1 |
| LoadDispatcher.sortCargos(List |
1 | 2 | 2 |
| LoadDispatcher.findCargo(List |
1 | 3 | 3 |
| InputValidator.validateInt(int, int, int) | 1 | 2 | 2 |
| InputValidator.validateDouble(double, double) | 1 | 2 | 2 |
| Main.main(String[]) | 1 | 6 | 6 |
| Total | 24 | 44 | 44 |
| Average | 1.00 | 1.83 | 1.83 |
可以看出最复杂的方法是Main.main(String[] args)
main 方法承担了整个程序的流程调度,包含大量控制流与逻辑分支
Bug分析
出现格式错误和部分货物超载,多货舱存在超载两个测试点错误的bug
格式错误经比对调试后改正测试点错误至今未知
第三次作业
作业要求
本次迭代新增约4个类,系统总类数达到10个左右。严禁使用继承和多态(无extends、无interface、无instanceof),请严格遵循以下关系与单一职责设计(违反设计要求则扣分):
新增类 职责划分 类间关系设计建议
Passenger 仅负责管理旅客姓名及计算旅客总重量(含标准体重) 与 Luggage 是组合关系。旅客登机必带行李(可为0kg),行李对象必须在 Passenger 构造器内部 new 出来,不对外暴露修改
Luggage 仅负责记录行李重量 作为 Passenger 的组成部分,体现类的细粒度拆分
WeightBalanceCalculator 纯计算工具类。仅负责根据航空力学公式计算总重量、总力矩、重心及百分比。 与 Flight 是依赖关系。该类不应有 Flight 的成员变量,必须将 Flight 对象作为 generateLoadSheet 方法的参数传入
InputValidator (优化) 剥离所有控制台的异常处理逻辑,提供统一的获取整数、浮点数的静态方法 与主流程是依赖关系
注:原有的 Flight 类需增加List
实现方式
第1行,航班号(字符串)
第2行,前舱货架行号(整型,≥0)
第3行,前舱货架列号(整型,≥0)
第4行,前舱最大载重量(实型,≥0.0)
第5行,后舱货架行号(整型,≥0)
第6行,后舱货架列号(整型,≥0)
第7行,后舱最大载重量(实型,≥0.0)
第8行,乘客人数n(整型,≥0)
从第9行开始,连续n行,输入每名乘客所携带行李重量(实型数,≥0.0)
货物总件数m(整型,≥0)
装载在前舱的货物件数p(整型,0≤p≤m)
接下来连续输入装载在前舱的p件货物的信息,分别为:
货物编号(整型,≥0)
货物重量(实型,≥0.0)
在输入装载在后舱的m-p件货物的信息,分别为:
货物编号(整型,≥0)
货物重量(实型,≥0.0)
代码规模
第三次作业的代码规模如下图。
| 源文件 | 总行数 | 代码行数 | 代码占比 | 注释行数 | 注释占比 | 空行数 | 空行占比 |
|---|---|---|---|---|---|---|---|
| Luggage.java | 10 | 8 | 80% | 1 | 10% | 1 | 10% |
| Passenger.java | 13 | 11 | 85% | 1 | 8% | 1 | 8% |
| Cargo.java | 12 | 10 | 83% | 1 | 8% | 1 | 8% |
| CargoCompartment.java | 24 | 21 | 88% | 1 | 4% | 2 | 8% |
| LoadDispatcher.java | 14 | 13 | 93% | 1 | 7% | 0 | 0% |
| InputValidator.java | 22 | 19 | 86% | 1 | 5% | 2 | 9% |
| BalanceResult.java | 13 | 11 | 85% | 1 | 8% | 1 | 8% |
| WeightBalanceCalculator.java | 25 | 23 | 92% | 1 | 4% | 1 | 4% |
| Flight.java | 20 | 17 | 85% | 1 | 5% | 2 | 10% |
| Main.java | 78 | 71 | 91% | 1 | 1% | 6 | 8% |
| 总计 | 231 | 204 | 88% | 10 | 4% | 17 | 7% |
类图
第三次作业类图如下

复杂度分析
第三次作业的复杂度分析如下。
| 方法 | ev(G) | iv(G) | v(G) |
|---|---|---|---|
| Luggage.Luggage(double) | 1 | 1 | 1 |
| Luggage.getWeight() | 1 | 1 | 1 |
| Passenger.Passenger(double) | 1 | 1 | 1 |
| Passenger.getTotalWeight() | 1 | 1 | 1 |
| Cargo.Cargo(int, double) | 1 | 1 | 1 |
| Cargo.getId() | 1 | 1 | 1 |
| Cargo.getWeight() | 1 | 1 | 1 |
| CargoCompartment.CargoCompartment(int, int, int, double) | 1 | 1 | 1 |
| CargoCompartment.addCargo(Cargo) | 1 | 1 | 1 |
| CargoCompartment.getCurrentWeight() | 1 | 2 | 2 |
| CargoCompartment.getId() | 1 | 1 | 1 |
| CargoCompartment.getMaxWeight() | 1 | 1 | 1 |
| CargoCompartment.getCargoList() | 1 | 1 | 1 |
| LoadDispatcher.sortCargo(List |
1 | 3 | 3 |
| InputValidator.readString() | 1 | 1 | 1 |
| InputValidator.readNonNegativeInt() | 1 | 2 | 2 |
| InputValidator.readRangeInt(int, int) | 1 | 2 | 2 |
| InputValidator.readNonNegativeDouble() | 1 | 2 | 2 |
| BalanceResult.BalanceResult(double, double, double, double, boolean) | 1 | 1 | 1 |
| BalanceResult.getTotalWeight() | 1 | 1 | 1 |
| BalanceResult.getTotalMoment() | 1 | 1 | 1 |
| BalanceResult.getActualCG() | 1 | 1 | 1 |
| BalanceResult.getCgPercent() | 1 | 1 | 1 |
| BalanceResult.isSafe() | 1 | 1 | 1 |
| WeightBalanceCalculator.generateLoadSheet(Flight) | 1 | 3 | 3 |
| Flight.Flight(String) | 1 | 1 | 1 |
| Flight.addPassenger(Passenger) | 1 | 1 | 1 |
| Flight.addCargoCompartment(CargoCompartment) | 1 | 1 | 1 |
| Flight.getPassengerTotalWeight() | 1 | 2 | 2 |
| Flight.getFlightNo() | 1 | 1 | 1 |
| Flight.getPassengers() | 1 | 1 | 1 |
| Flight.getCargoCompartments() | 1 | 1 | 1 |
| Main.main(String[]) | 1 | 6 | 6 |
| Main.checkCapacity(CargoCompartment) | 1 | 2 | 2 |
| Main.printSheet(Flight, BalanceResult) | 1 | 5 | 5 |
| Total | 35 | 54 | 57 |
| Average | 1.03 | 1.59 | 1.68 |
对于其中几个比较复杂的方法,分析如下:
1.Main.main ()
功能
程序入口,负责全部输入读取、对象创建、流程调度、业务启动。
2.Main.printSheet ()
打印完整载重平衡舱单,输出所有数据与安全结论。
3.LoadDispatcher.sortCargo ()
使用冒泡排序对货物按 ID 升序排序。
Bug分析
出现三个测试点的错误
分析后原因可能如下:
- 货物排序方式不对。
- 货舱 1 和货舱 2 的力臂计算错误。
经修改后仍显示错误。
思考总结
在前三次作业的学习中,自我感觉自己的对需求的分析以及之后的代码实践编程能力仍然不足有待进步,希望在后续的学习中能不断精进,突破自己。

浙公网安备 33010602011771号