航空货运管理系统总结
一、前言:
这一次的题目集8-9,主要围绕航空货运管理系统迭代升级进行展开。这次的大作业与上一次电梯类相比难度降低了不少。在有了第一次大作业的练习后,在完成这一次大作业就轻松许多。相较于第一次大作业,这一次航空货运管理系统没有复杂的算法逻辑,主要考察了面向对象编程的四大原则:
1.单一职责原则(Single Responsibility Principle, SRP):一个类应该仅有一个引起它变化的原因(即一个类只负责一项职责)。
2.开闭原则(Open/Closed Principle, OCP):软件实体(类、模块、函数等)应该对扩展开放(即通过新增代码实现功能扩展),对修改关闭(即不修改已有代码逻辑)。
3.里氏替换原则(Liskov Substitution Principle, LSP):子类必须能够替换其父类,且程序的行为不变(子类需遵循父类的契约)。其中子类方法的前置条件(参数)不能比父类更严格,后置条件(返回值 / 异常)不能比父类更宽松。
4.合成复用原则(Composite Reuse Principle, CRP):优先使用组合(Composition)或聚合(Aggregation)而非继承来实现代码复用。
通过这一次大作业的练习,我学习到了很多东西,例如抽象类的使用,对继承与多态进一步的理解,了解到了面向对象编程的几大原则,并学会在编程的过程中如何应用这四大原则。
二、设计与分析:
- 第一次题目集:
(1)题目分析:
这次题目模拟某客户到该航空公司办理一次货运业务的过程,需要实现计费重量、运费的计算以及订单信息的输出。并且设计过程要满足面向对象编程的四大原则(单一职责、里氏代换、开闭、合成复用)。核心思想包括计费重量的计算、实施分段费率以及订单信息的处理。
(2)类设计方案:

- 支付模块:
Payment 抽象类定义支付接口,WechatPay、AliPay 实现具体支付逻辑,支持支付方式扩展(如下一次题目中的现金支付的扩展)。
点击查看代码
//支付方式
abstract class Payment{
abstract void pay(double amount);
}
//微信支付
class WechatPay extends Payment{
public WechatPay(){
}
@Override
public void pay(double amount) {
System.out.printf("微信支付金额:%.1f\n\n",amount);
}
}
//支付宝支付
class AliPay extends Payment{
public AliPay() {
}
@Override
public void pay(double amount) {
System.out.printf("支付宝支付金额:%.1f\n\n",amount);
}
}
点击查看代码
class Product{
private int productID;//产品编号
private String name;//产品名
private double length;//产品的长度
private double width;//产品的宽度
private double height;//产品的高度
private double weight;//产品的重量
public Product(int productID,String name,double length,double width,double height,double weight){
this.name=name;
this.productID=productID;
this.length=length;
this.width=width;
this.height=height;
this.weight=weight;
}
public int getProductID() {
return productID;
}
public void setProductID(int productID) {
this.productID = productID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public double getLength() {
return length;
}
public double getWeight() {
return weight;
}
public double getWidth() {
return width;
}
public void setHeight(double height) {
this.height = height;
}
public void setLength(double length) {
this.length = length;
}
public void setWeight(double weight) {
this.weight = weight;
}
public void setWidth(double width) {
this.width = width;
}
//计算货物计费重量
public double getChargeWeight(){
double volumeWeight=length*height*width/6000;
return Math.max(volumeWeight,weight);
}
}
- Customer、Sender、Receiver:顾客信息类,存储用户信息(姓名、电话、地址)。
点击查看代码
//客户类
class Customer{
private String name;//姓名
private String phone;//电话
private String address;//地址
private int id;//编号
public Customer(String name, String phone, String address, int id) {
this.name = name;
this.phone = phone;
this.address = address;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
- Flight:航班类,管理航班载重,canAccept 检查超重(currentLoad + 货物重量 ≤ maxLoad)。
点击查看代码
//航班类
class Flight{
private String number;//航班号
private String departure; // 航班出发地
private String arrival;// 航班目的地
private String date;// 航班日期
private double maxLoad;// 航班的最大载重
private double currentLoad;// 航班的当前载重
public Flight(String number, String departure, String arrival, String date, double maxLoad) {
this.number = number;
this.departure = departure;
this.arrival = arrival;
this.date = date;
this.maxLoad = maxLoad;
// 初始时当前载重为 0
this.currentLoad = 0;
}
public String getNumber() {
return number;
}
public String getDeparture() {
return departure;
}
public String getArrival() {
return arrival;
}
public String getDate() {
return date;
}
public double getMaxLoad() {
return maxLoad;
}
public double getCurrentLoad() {
return currentLoad;
}
//判断是否超重
public boolean canAccept(double weight){
return currentLoad + weight <= maxLoad;
}
public void setNumber(String number) {
this.number = number;
}
public void setDeparture(String departure) {
this.departure = departure;
}
public void setArrival(String arrival) {
this.arrival = arrival;
}
public void setDate(String date) {
this.date = date;
}
public void setMaxLoad(double maxLoad) {
this.maxLoad = maxLoad;
}
public void setCurrentLoad(double currentLoad) {
this.currentLoad = currentLoad;
}
//向航班添加货物载重
public void addLoad(double weight) {
if (!canAccept(weight)) {
return;
}
currentLoad += weight;
}
}
- Order:订单类,关联业务对象(客户、航班、货物等)。
点击查看代码
//订单类
class Order{
private String orderId;//订单编号
private String date;//订单日期
private Customer customer;//下单顾客
private Flight flight;//订单中的航班
private List<Product> cargos= new ArrayList<>();;//货物列表
private Sender sender;//发件人
private Receiver receiver;//收件人
public Order(String orderId, String date, Customer customer, Flight flight, Sender sender, Receiver receiver) {
this.orderId = orderId;
this.date = date;
this.customer = customer;
this.flight = flight;
this.sender = sender;
this.receiver = receiver;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Flight getFlight() {
return flight;
}
public void setFlight(Flight flight) {
this.flight = flight;
}
public List<Product> getCargos() {
return cargos;
}
public void setCargos(List<Product> cargos) {
this.cargos = cargos;
}
public Sender getSender() {
return sender;
}
public void setSender(Sender sender) {
this.sender = sender;
}
public Receiver getReceiver() {
return receiver;
}
public void setReceiver(Receiver receiver) {
this.receiver = receiver;
}
//求出货物的总重量
public double getTotalWeight(){
double totalWeight = 0;
for(Product cargo:getCargos()){
totalWeight+=cargo.getChargeWeight();
}
return totalWeight;
}
//航班是否能承载订单中所有货物
public boolean validateFlightCapacity() {
return flight.canAccept(getTotalWeight());
}
//计算订单的总运费
public double getRate(double weight){
double rate=0;
// 根据货物的计费重量确定费率
if (weight < 20.0) {
rate = 35;
} else if (weight < 50.0) {
rate = 30;
} else if (weight < 100.0) {
rate = 25;
} else {
rate = 15;
}
return rate;
}
//向订单中添加货物
public void addCargo(Product cargo) {
cargos.add(cargo);
}
}
(3)代码分析:

- 代码行数:
- 总行数 529,可执行语句 256(核心逻辑占比约 48%),分支语句占比 2.7%(条件判断少,流程线性)。
- 类与方法:
- 平均每个类含 6 个方法(如 Order 类封装订单逻辑,Product 类处理货物计算,职责明确)。
- 平均每个方法 3.37 行(方法粒度细,符合单一职责原则,如 Sender/Receiver 的 getter/setter 方法简洁)。
- 方法复杂度:
- 最复杂方法为 Main.main()(行号 295,复杂度 2.3),因处理多步输入(客户、货物、航班等信息),逻辑线性但步骤多,需注意输入顺序和异常处理。
- outPut.generateReport()(复杂度 2.1)处理订单报告生成,循环输出货物明细,涉及字符串格式化,需确保数据一致性。
- 嵌套深度:
- 最大块深度 3(如 Main.main 中的循环嵌套),平均块深度 0.91(代码结构扁平,可读性好,大部分代码无嵌套或浅嵌套)。
- 直方图显示块深度集中在 0-3,说明代码结构简单,无复杂嵌套逻辑。
(4)代码质量与改进
- 优点:
- 低复杂度:平均复杂度 1.11,代码逻辑较为简单,没有复杂的算法逻辑。
- 职责单一:类和方法分工明确,每一个类的职责分明,没有类与类的重叠(如 Product 计算计费重量,Flight 管理载重,Order 处理订单逻辑),符合面向 对象设计原则。
- 类图匹配:代码与 PowerDesigner 类图完全映射(继承、关联关系均实现,如 WechatPay 继承 Payment,Order 关联 Customer/Flight 等)。
- 改进点:
- 对输入异常进行处理:在main函数中并没有对异常输入进行处理,可以设置try-catch模块进行处理。
- 支付方式多样化:在outPut.generateReport 固定了WeChat的支付方式,不利于后期代码的迭代。
- 代码冗余:Sender 和 Receiver 类属性重复,可以设计Person父类,减少代码的重复性。
2.第二次题目集:
(1)题目分析:
这一次的题目集围绕上一次题目中的航空货运管理系统进行迭代升级。与上一次题目集相比,这一次题目增加了许多新的要求:
- 费率计算:新增货物类型维度(普通 / 危险 / 加急),每种类型独立费率表。
- 客户类型:新增个人用户 / 集团用户,订单总运费享受固定折扣(9 折 / 8 折)。
- 支付方式:新增现金支付选项。
- 输入输出调整:输入包含客户类型、货物类型,输出显示支付方式全称。
(2)类设计方案:

- 支付模块修改:新增CashPay类,可以支持现金支付,outPut.generateReport 通过 switch 动态选择支付方式,提高了代码的扩展性。
点击查看代码
class CashPay extends Payment{
public CashPay(){}
public void pay(double amount){
System.out.printf("现金支付金额:%.1f\n\n", amount);
}
}
(3)代码分析:

- 新版本总行数 612(+83),语句数 318(+62),主要因新增支付、类型、折扣逻辑。
- 最复杂方法:outPut.generateReport(复杂度 5.23,原 2.1),因处理支付选择、折扣、多费率计算,逻辑更复杂(需拆分优化,如提取支付创建、折扣计算为子方法)。
- 类数 7(+1,新增 CashPay),平均方法数 / 类 11.29(+5.29,Order 类新增 getRate、getDiscount 等,功能更丰富)。
- 块深度与复杂度:平均块深度 1.13(+0.22,switch 嵌套),平均复杂度 1.25(+0.14),仍可控(直方图显示深度≤4,可读性良好)。
(4)代码改进:
- 方法拆分:将 outPut.generateReport 中的支付创建、折扣计算、费率逻辑提取为子方法(如 createPayment、calculateDiscount、computeRate),降低其复杂度(当前 5.23 较高,拆分后可提升可读性和可维护性)。
- 注释补充:对费率规则(货物类型、重量分段)、折扣逻辑(客户类型映射)添加注释,使代码与类图的业务规则更清晰,便于后续维护。
- 异常处理:在输入解析(如 Integer.parseInt)处添加 try-catch,增强健壮性。
四、采坑心得
(1)输入错误:
在第一次完成代码开始运行时,在我将PTA中的输入类型复制到IDEA上时就立马报错。

起初我以为是因为我直接复制了输入内容而导致的输入错误,但在我手动输入到货物数量时还是报错。在调试的不知道多少次后我还是不知道到底为什么出错。在求助了AI后,我才找到了原因

虽然改错的过程确实很痛苦,但是这也是对自己知识的一种提升,能够在之后的学习中避免再次发生类似的错误。
(2)格式错误:
在改错后我继续提交代码,结果显示在异常测试点出现格式错误。
在自己尝试了很多次后,我一直没有该对。于是我在PTA的讨论区提问。

也谢谢其他同学的回答,让我才知道原来是这么简单的问题困扰了我这么长时间(╥╯^╰╥)


从这里可以看出,编写程序不仅需要扎实的知识,还要注意到一些小细节。同时,与同学交流也是及其重要的。有时候别人的一句话就可能解答困扰你很久的问题。
五、总结
这次航空货运管理系统,总体来说,难度与上一次电梯类相比减小了不少。这次的大作业主要考察了抽象类的使用,继承与多态,以及面向对象的四大法则。经过这两次大作业的磨炼,我整体的编程水平有了不小的提升。但还有不少需要改进的地方。例如代码冗余问题,在大作业中有部分类内容重复,还有一些没有调用的函数;以及未对异常输入进行处理等等。不过正是这些不足之处,使得我明确了接下来需要学习的内容:比如学习更多的设计模式,以此来让代码具备更高的灵活性,再比如学习单元测试方面的知识,从而让代码的可靠性得以提升。