PTA题目集8~9的总结性Blog
📈 航空运输分析
基于PTA题集中的8~9的总结性Blog总结。
■ 前言
PTA8三个题目分别是点线面、雨刷和航空运输;PTA9三个题目是魔方、点线面和航空运输,整体都不难。前两题都给出了类图,照着写就行,而航空运输就需要根据要求、提示和前两题的类图模仿着自己设计类图,写出每个方法是比较简单的,有点乱的就是类之间的关系还有四个原则,单一职责原则,开闭原则,里氏替换原则,依赖倒置原则,写着写着就容易忘。之后的分析也是针对航空运输这个更具代表性的题。
⚙️ 设计与分析
第一次代码里,几乎所有类都只有成员、构造方法和getter、setter,另外是一个负责输入的主类和一个负责计算的计算类;第二次根据新要求改了一点逻辑并加了支付方式的类。
📌 第一次航空运输数据

Metrics Details For File 'Main.java'
--------------------------------------------------------------------------------------------
Parameter Value
========= =====
Project Directory D:\java_project\project000\PTA8\src\com\zephyr\three\
Project Name two
Checkpoint Name Baseline
File Name Main.java
Lines 299*
Statements 224
Percent Branch Statements 5.8
Method Call Statements 41
Percent Lines with Comments 3.3
Classes and Interfaces 10
Methods per Class 8.90
Average Statements per Method 1.45
Line Number of Most Complex Method 145
Name of Most Complex Method GoodsCalc.getAddress()
Maximum Complexity 7
Line Number of Deepest Block 196
Maximum Block Depth 4
Average Block Depth 1.60
Average Complexity 1.38
--------------------------------------------------------------------------------------------
Most Complex Methods in 9 Class(es): Complexity, Statements, Max Depth, Calls
Client.Client() 1, 4, 2, 0
Client.Client() 1, 0, 0, 0
Client.getName() 1, 1, 2, 0
Client.getPhone() 1, 1, 2, 0
Flight.getAddress() 1, 1, 2, 0
Flight.getAddress() 1, 5, 2, 0
Flight.getAddress() 1, 0, 0, 0
Goods.getAddress() 1, 1, 2, 0
Goods.getAddress() 1, 1, 2, 0
Goods.getAddress() 1, 1, 2, 0
Goods.getAddress() 1, 1, 2, 0
Goods.getAddress() 1, 1, 2, 0
Goods.getAddress() 1, 1, 2, 0
Goods.getAddress() 1, 7, 2, 0
Goods.getAddress() 1, 0, 0, 0
GoodsCalc.getAddress() 3, 5, 4, 2
GoodsCalc.getAddress() 3, 5, 4, 2
GoodsCalc.getAddress() 1, 3, 2, 0
GoodsCalc.getAddress() 7, 11, 2, 0
GoodsCalc.getAddress() 2, 4, 3, 2
GoodsCalc.getAddress() 1, 0, 0, 0
Main.main() 3, 36, 3, 26
Order.getAddress() 1, 1, 2, 0
Order.getAddress() 1, 1, 2, 0
Order.getAddress() 1, 1, 2, 0
Order.getAddress() 1, 1, 2, 0
Order.getAddress() 1, 4, 2, 0
Order.getAddress() 1, 0, 0, 0
Receiver.getAddress() 1, 1, 2, 0
Receiver.getName() 1, 1, 2, 0
Receiver.getPhone() 1, 1, 2, 0
Receiver.Receiver() 1, 3, 2, 0
Receiver.Receiver() 1, 0, 0, 0
ReportForm.getAddress() 3, 15, 4, 8
ReportForm.getAddress() 1, 5, 2, 0
Sender.getAddress() 1, 1, 2, 0
Sender.getName() 1, 1, 2, 0
Sender.getPhone() 1, 1, 2, 0
Sender.Sender() 1, 3, 2, 0
Sender.Sender() 1, 0, 0, 0
--------------------------------------------------------------------------------------------
Block Depth Statements
0 13
1 83
2 113
3 11
4 4
5 0
6 0
7 0
8 0
9+ 0
--------------------------------------------------------------------------------------------
📌 第二次航空运输数据

Metrics Details For File 'Main.java'
--------------------------------------------------------------------------------------------
Parameter Value
========= =====
Project Directory D:\java_project\project000\PTA9\src\three\
Project Name 航空运输2
Checkpoint Name Baseline
File Name Main.java
Lines 437*
Statements 313
Percent Branch Statements 8.9
Method Call Statements 55
Percent Lines with Comments 1.8
Classes and Interfaces 10
Methods per Class 7.30
Average Statements per Method 4.08
Line Number of Most Complex Method 238
Name of Most Complex Method Goods.calcRate()
Maximum Complexity 22
Line Number of Deepest Block 113
Maximum Block Depth 4
Average Block Depth 1.73
Average Complexity 1.45
--------------------------------------------------------------------------------------------
Most Complex Methods in 10 Class(es): Complexity, Statements, Max Depth, Calls
Client.Client() 1, 5, 2, 0
Client.discount() 2, 3, 3, 1
Client.getAddress() 1, 1, 2, 0
Client.getId() 1, 1, 2, 0
Client.getName() 1, 1, 2, 0
Client.getPhone() 1, 1, 2, 0
Client.getType() 1, 1, 2, 0
Client.setAddress() 1, 1, 2, 0
Client.setId() 1, 1, 2, 0
Client.setName() 1, 1, 2, 0
Client.setPhone() 1, 1, 2, 0
Client.setType() 1, 1, 2, 0
Flight.Flight() 1, 5, 2, 0
Flight.getDate() 1, 1, 2, 0
Flight.getEnd() 1, 1, 2, 0
Flight.getId() 1, 1, 2, 0
Flight.getMax() 1, 1, 2, 0
Flight.getStart() 1, 1, 2, 0
Flight.setDate() 1, 1, 2, 0
Flight.setEnd() 1, 1, 2, 0
Flight.setId() 1, 1, 2, 0
Flight.setMax() 1, 1, 2, 0
Flight.setStart() 1, 1, 2, 0
Goods.calcPrice() 1, 1, 2, 1
Goods.calcRate() 22, 35, 4, 4
Goods.calcWeight() 2, 4, 3, 0
Goods.getHeight() 1, 1, 2, 0
Goods.getId() 1, 1, 2, 0
Goods.getLength() 1, 1, 2, 0
Goods.getName() 1, 1, 2, 0
Goods.getWeight() 1, 1, 2, 0
Goods.getWidth() 1, 1, 2, 0
Goods.Goods() 1, 7, 2, 0
Goods.setHeight() 1, 1, 2, 0
Goods.setId() 1, 1, 2, 0
Goods.setLength() 1, 1, 2, 0
Goods.setName() 1, 1, 2, 0
Goods.setWeight() 1, 1, 2, 0
Goods.setWidth() 1, 1, 2, 0
Main.main() 2, 37, 3, 30
Order.getDate() 1, 1, 2, 0
Order.getId() 1, 1, 2, 0
Order.getPayment() 1, 1, 2, 0
Order.getReceiver() 1, 1, 2, 0
Order.getSender() 1, 1, 2, 0
Order.Order() 1, 5, 2, 0
Order.setDate() 1, 1, 2, 0
Order.setId() 1, 1, 2, 0
Order.setPayment() 1, 1, 2, 0
Order.setReceiver() 1, 1, 2, 0
Order.setSender() 1, 1, 2, 0
OrderInformation.getTotalPriceCalc() 2, 5, 3, 1
OrderInformation.getTotalWeightCalc() 2, 5, 3, 1
OrderInformation.show() 4, 16, 4, 12
Payment.getPayment() 1, 1, 2, 0
Payment.Payment() 1, 1, 2, 0
People.getAddress() 1, 1, 2, 0
People.getName() 1, 1, 2, 0
People.getPhone() 1, 1, 2, 0
People.People() 1, 3, 2, 0
People.setAddress() 1, 1, 2, 0
People.setName() 1, 1, 2, 0
People.setPhone() 1, 1, 2, 0
Receiver.Receiver() 1, 1, 2, 1
Sender.Sender() 1, 1, 2, 1
--------------------------------------------------------------------------------------------
Block Depth Statements
0 21
1 107
2 138
3 30
4 17
5 0
6 0
7 0
8 0
9+ 0
--------------------------------------------------------------------------------------------
🔍 两次航空运输代码分析
以下是对两次航空运输代码分析结果的整理与总结,从基本信息、复杂度指标、方法复杂度及嵌套深度分布等维度对比分析代码质量变化:
➤ 基本信息对比
| 指标 | 第一次分析 | 第二次分析 | 变化趋势 |
|---|---|---|---|
| 文件名称 | Main.java |
Main.java |
无变化 |
| 代码行数(Lines) | 299* | 437* | 增加138行(+46%) |
| 语句总数(Statements) | 224 | 313 | 增加89句(+40%) |
| 类和接口数 | 10 | 10 | 无变化 |
| 每个类的平均方法数 | 8.90 | 7.30 | 减少1.6个(-18%) |
| 每个方法的平均语句数 | 1.45 | 4.08 | 增加2.63句(+181%) |
➤ 代码复杂度相关指标对比
| 指标 | 第一次分析 | 第二次分析 | 变化趋势 |
|---|---|---|---|
| 分支语句占比(%) | 5.8% | 8.9% | 增加3.1%(+53%) |
| 方法调用语句数 | 41 | 55 | 增加14次(+34%) |
| 注释行占比(%) | 3.3% | 1.8% | 减少1.5%(-45%) |
| 最大复杂度(Maximum Complexity) | 7 | 22 | 显著增加15(+214%) |
| 平均复杂度(Average Complexity) | 1.38 | 1.45 | 微增0.07(+5%) |
| 最大嵌套深度(Maximum Block Depth) | 4 | 4 | 无变化 |
| 平均嵌套深度(Average Block Depth) | 1.60 | 1.73 | 微增0.13(+8%) |
➤ 最复杂方法对比
第一次分析
- 最复杂方法:
GoodsCalc.getAddress()- 复杂度:7
- 语句数:11
- 嵌套深度:2
- 方法调用数:0
第二次分析
- 最复杂方法:
Goods.calcRate()- 复杂度:22
- 语句数:35
- 嵌套深度:4
- 方法调用数:4
变化特点:
- 最复杂方法的复杂度从7跃升至22,语句数从11增加到35,嵌套深度从2提升至4,表明该方法逻辑显著复杂化,可能存在代码可读性和维护性风险。
Main.main()方法的复杂度从3降至2,但语句数从36增加到37,说明主函数可能更冗长,但逻辑复杂度略有降低。
➤ 嵌套深度与语句数分布对比
第一次分析
| 嵌套深度 | 语句数 | 占比 |
|---|---|---|
| 0 | 13 | 5.8% |
| 1 | 83 | 37.1% |
| 2 | 113 | 50.4% |
| 3 | 11 | 4.9% |
| 4 | 4 | 1.8% |
第二次分析
| 嵌套深度 | 语句数 | 占比 |
|---|---|---|
| 0 | 21 | 6.7% |
| 1 | 107 | 34.2% |
| 2 | 138 | 44.1% |
| 3 | 30 | 9.6% |
| 4 | 17 | 5.4% |
变化特点:
- 嵌套深度为0和1的语句占比略有下降,嵌套深度2的语句占比从50.4%降至44.1%,而嵌套深度3和4的语句占比分别从4.9%、1.8%提升至9.6%、5.4%,表明代码中中深层嵌套(3-4层)的逻辑增加,可能导致代码结构复杂化。
➤ 关键问题诊断
1. 复杂度飙升
- 问题:第二次分析中
Goods.calcRate()方法复杂度高达22(远超建议阈值10),语句数35行,嵌套深度4层,可能存在逻辑过于集中、条件判断复杂等问题,影响可读性和调试效率。
2. 注释行占比下降
- 问题:注释行占比从3.3%降至1.8%,代码自解释性可能降低,后续维护成本增加。
3. 方法规模增大
- 问题:每个方法的平均语句数从1.45增至4.08,部分方法(如
Main.main())语句数超过30行,违反“单一职责原则”。
4. 分支逻辑增加
- 问题:分支语句占比从5.8%增至8.9%,可能导致代码路径复杂度上升。
🔴 复杂度失控(Goods.calcRate 22 → 阈值<10)
// 典型问题代码(硬编码+多层嵌套)
public void calcRate() {
if (type == 1) { // 层级1
for (Item item : items) { // 层级2
if (weight > 100) { // 层级3
switch(region) { // 层级4
case "A": rate = 0.8; break;
// 新增地区需修改源码(违反开闭原则)
}
}
}
}
}
🟠 类设计缺陷
- Client类:12个方法(7个Getter/Setter)
// 数据类特征明显(无业务方法) class Client { private String id; public String getId() { return id; } // 冗余方法×12 } - OrderInformation类:混合计算与展示逻辑
class OrderInformation { void calculateTotal() { /* 计算逻辑 */ } void printReceipt() { /* 打印逻辑 */ } // 违反单一职责 }
🟡 注释危机
- 核心方法零注释:
Goods.calcRate()(35行关键算法无解释)
Main.main()(37行主流程无说明) - 类文档缺失:10个类中仅2个有类级注释
➤ 两次次迭代代码质量演进分析📊
| 指标 | 第一次迭代 | 第二次迭代 | 健康阈值 | 趋势 | 问题等级 |
|---|---|---|---|---|---|
| 最复杂方法复杂度 | 7 | 22 | <10 | ↗恶化 | 🔴 |
| 注释覆盖率 | 3.3% | 1.8% | ≥20% | ↘恶化 | 🔴 |
| 类平均方法数 | 8.90 | 7.30 | ≤5 | →停滞 | 🟠 |
| Main方法调用数 | 26 | 30 | ≤10 | ↗恶化 | 🟠 |
第二次要求多了一些,各个指标恶化一点也情有可原,但看起来不止一点,是有点严重了。
这两次次写的时候其实都对那几个原则没有多少概念,从理解原则到遵守原则,还是有一定距离,因为写的时候总是会忽略,按照自己的习惯去写,代码看起来简洁就觉得没怎么违反原则。就像第一次代码里,几乎所有类都只有成员、构造方法和getter、setter。另外加个专门计算的类,而主函数负责输入。这样看起来似乎非常清晰明了,只有 输入,计算,和 约等于什么方法都没有的类 三种东西。而那些个类别说单一职责了,纯粹的不能再纯粹地负责了零个职责。
写的时候输入中没有对支付方式的选择,所以第一次写的时候并没有写相关的支付方式的类,在第二次有对应输入的时候才加进去的。
再看开闭原则,重写就跟大换血一样,到处删删改改,并没有做到对修改关闭,拓展性也比较低,基本是根据新要求从头到尾改一遍。
里氏替换和依赖倒置的话,第一次代码写了一个接口,第二次代码里有两个继承,因为本身写的就这么点,也没什么机会犯错,应该是没有违反的。
🌟 采坑心得
主要是刚开始自己设计代码的时候有点找不到方向,边写边改边设计,依赖、关联、聚合、组合、继承、多态、接口、单一职责原则、开闭原则、里氏替换原则、、依赖倒置原则四个原则,一下子忙不过来,顾此失彼。
📝 改进建议
- 为复杂方法、关键逻辑段添加注释,说明业务逻辑或算法思路。
- 避免冗余注释,但保留必要的设计决策说明。
- 将复杂逻辑拆分为更小的方法(如提取独立计算逻辑)。
- 减少多层条件嵌套。
- 将主函数中的业务逻辑拆分为独立服务类(如订单处理、费率计算等)。
- 确保每个方法专注于单一功能,语句数控制在20行以内。
- 使用策略模式(Strategy Pattern)替代多层
if-else或switch分支。 - 对条件表达式进行抽象,提升逻辑清晰度。
📖 总结
从两次分析对比来看,第二次代码在规模和复杂度上均有显著增长,尤其是核心业务逻辑方法(如费率计算)的复杂度大幅提升,可能带来维护风险。之后写代码应该优先对高复杂度方法进行重构,优化代码结构,增加必要注释,并遵循面向对象设计原则(如单一职责、开闭原则),以提升代码的可维护性和可扩展性。

浙公网安备 33010602011771号