航空货运管理系统总结性blog
1.前言:
(1)知识点对比
第一次航空货运管理系统:考察基础类设计、封装、构造方法、成员变量访问控制、简单业务逻辑计算,如计费重量、运费。
第二次航空货运管理系统:考察抽象类、继承、多态、方法重写,客户类型与货物类型更加多种多样、包括多种支付方式,引入了Customer和Cargo抽象类,通过子类实现多种类型的货物和客户。
(2)题量与难度
题量:两次题目输入输出格式相似,第二次在第一次的基础上新增客户类型个人用户Individual和集团用户Corporate、货物类型普通货物Normal、加急货物Expedite和危险货物Dangerous、支付方式微信支付Wechat、支付宝支付ALiPay和现金支付Cash的处理,所需要输入的参数更多,如客户类型、货物类型、支付方式。
难度:
第一次:基础类设计,逻辑集中在Order类,难度中等。
第二次:需要设计抽象类,需要考虑多种因素对费用的影响,如货物类型影响费率,客户类型影响折扣,难度提升至较难。
2.设计与分析:
(1)第一次航空货运管理系统
类图:

核心类:
Cargo:货物类,存储货物信息,属性包括货物编号、货物名称、货物宽度、货物长度、货物高度、货物重量,一个构造方法,方法包括getter和setter方法以及计算体积重量calculateVolumeWeight和计费重量方法calculateChargeableWeight。
Flight:航班类,存储航班信息,属性包括航班号、航班起飞机场、航班降落机场、航班日期、航班最大载重量,一个构造方法,方法包括getter和setter方法。
Customer:客户类,存储客户信息,属性包括客户编号、客户姓名、客户电话、客户地址、运送货物数量,一个构造方法,方法包括getter和setter方法。
Shipment:运输信息类,存储订单发货和收货信息,属性包括发件人地址,发件人姓名,发件人电话,收件人地址,收件人姓名,收件人电话,订单日期,航班,一个构造方法,方法包括getter和setter方法。
Order:订单类,计算总运费和生成报表,属性包括订单编号,括号,运输信息,货物数组,一个构造方法,方法包括计算费率getRate,计算总重calculateTotalWeight,计算总费用calculateBaseFreight,生成报表Report。
分析:
程序首先读取客户的基本信息,依次读取客户编号、姓名、电话、地址,然后创建 Customer 对象。
程序读取货物数量,创建 Cargo 数组,循环读取每件货物的详细信息并创建对象,sc.nextLine() 用于清除输入缓冲区的换行符。
依次读取航班号、起降机场、日期、最大载重量,创建 Flight 对象。
读取订单编号、日期、收发件人信息和收件人的详细信息,创建 Shipment 对象。
程序将客户、货运单和货物信息整合到 Order 对象中,并验证总重量是否超过航班限制,如果订单中货物重量超过航班剩余载重量,程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order.。
order类通过cargos[i].calculateChargeableWeigh获取重量,再用order类里面的getRate获取费率,在calculateBaseFreight方法中用for循环把费用相加totalFreight += chargeableWeight * rate,最后按格式生成报表。
扩展性:新增货物类型(如FragileCargo)或客户类型(如VIPCustomer)时,只需创建新子类,无需修改现有代码。客户折扣通过Customer子类实现,支持动态扩展(如新增学生客户享 7 折)。相比第一次,代码的可维护性和扩展性得到显著提升,同时减少了硬编码和重复逻辑
费率计算代码在Order的getRate方法中,若新增货物类型需修改该方法,违反开闭原则。
Order类承担过多职责,同时承担订单信息管理、运费计算、输出格式化三项职责,其中 Report() 方法包含大量输出逻辑,违反单一职责原则,圈复杂度较高,代码可维护性差。
(2)第二次航空货运管理系统
类图:

核心类:
Cargo:货物类,Cargo 定义为抽象类,属性和第一次的一样,新增抽象方法 getRate(double weight),由子类实现具体费率计算逻辑。
子类实现:
普通货物NormalCargo:阶梯费率为 35/30/25/15 元 /kg。
加急货物ExpediteCargo:阶梯费率为 60/50/40/30 元 /kg。
危险品货物DangerousCargo:阶梯费率为 80/50/30/20 元 /kg。
核心方法:
calculateVolumeWeight():计算体积重量(长 × 宽 × 高 / 6000)。
calculateChargeableWeight():取实际重量与体积重量的较大值作为计费重量。
Flight:航班类属性与方法与第一次相似,提供 getter 方法获取信息,仅作为数据载体。
Customer:客户类定义为抽象类,属性与第一次相似,新增抽象方法 getRate() 用于计算客户折扣
子类实现:
个人用户IndividualCustomer:折扣率 0.9。
集团用户CorporateCustomer:折扣率 0.8。
Shipment:运输信息类,属性与第一次相似,方法包括 getter 方法获取运输相关信息。
Order:订单类负责计算总运费,含客户折扣和总计费重量,将费率计算方法改到Cargo 子类中,使设计更加合理,通过多态实现不同货物类型的费率计算。
核心方法:
calculateBaseFreight():遍历货物数组,调用 Cargo.getRate() 获取单件货物费率,累加后应用客户折扣。
calculateTotalWeight():累加所有货物的计费重量。
Report:报表类独立负责订单报表的生成与输出,从订单类中分离开,符合单一职责原则,使设计更加合理。
核心方法:
show() 方法按格式打印订单详情、收发件人信息、货物明细及支付方式包括支付宝、微信、现金。
分析:
与第一次相比,第二次改为
根据客户类型创建对应对象:
if (khlx.equals("Individual")) {
customer = new IndividualCustomer(bh, xm, dh, dz); // 个人客户,折扣率0.9
} else {
customer = new CorporateCustomer(bh, xm, dh, dz); // 企业客户,折扣率0.8
}
for循环读取每件货物的详细信息并创建相应的对象:
if(hwlx.equals("Normal")) {
cargo = new NormalCargo[hwsl]; // 普通货物数组
} else if (hwlx.equals("Expedite")) {
cargo = new ExpediteCargo[hwsl]; // 加急货物数组
} else {
cargo = new DangerousCargo[hwsl]; // 危险货物数组
}
(支付方式转换逻辑: ALiPay →"支付宝", Wechat →"微信",其他→"现金")
相比第一次设计模式优化
费率计算更加合理:
将原 Order 类中的 getRate() 逻辑抽取到 Cargo 子类中,通过多态实现不同货物类型费率不同,符合开闭原则,新增货物类型无需修改原有代码。
单一职责原则:
Order 类仅负责运费计算,剥离报表生成逻辑到独立的 Report 类。
Shipment 类专注于运输信息,Flight 类专注于航班数据,职责清晰。
存在的问题
3.踩坑心得:
(1)输入缓冲区残留问题:
问题:使用 sc.nextInt() 读取整数后未消耗换行符,导致后续 sc.nextLine() 读取空字符串,引发 NullPointerException。
解决:在每次 nextInt() 后强制调用 sc.nextLine() 清除缓冲区,例如:
int hwsl = sc.nextInt();
sc.nextLine(); // 关键操作,避免换行符干扰后续输入
(2)开始没有考虑重量超过航班剩余载重量,导致部分测试点过不去
如果订单中货物重量超过航班剩余载重量程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order. ,程序终止运行。
(3)第一次时把getRate()放在了订单类order中,导致在第二次新增了货物类型后,不能处理多种不同费率的计算,没有把getRate()放在正确的地方
(4)Order类同时承担订单信息管理、运费计算、输出格式化三项职责,其中 Report() 方法包含大量输出逻辑,违反单一职责原则,在第二次代码中把Report从订单类order中分离,让类设计更加合理。
4.改进建议:
(1)引入工厂模式解耦对象创建
将客户和货物的创建逻辑封装到工厂类中,避免 main 方法中大量 if-else 判断
(2)使用枚举优化
将客户类型、货物类型、支付方式定义为枚举,避免字符串硬编码
2. 异常处理增强
输入校验:增加对货物数量、重量、尺寸的合法性校验(如非负数),避免IllegalArgumentException。
5.总结:
在这两次航空货运管理系统中,我我对面向对象编程的设计原则和实践有了更深入的理解,第一次教训:将货物费率硬编码在Order类中,新增货物类型时需修改核心类,违反开闭原则。第二次改进:通过抽象类Cargo定义getRate()接口,由子类(NormalCargo/ExpediteCargo)实现具体费率逻辑。新增货物类型时只需创建新子类,无需修改原有代码。第一次问题:Order类同时负责运费计算、订单数据管理和报表输出,导致类复杂度高(圈复杂度 5)。第二次优化:剥离报表逻辑到独立的Report类,专注输出格式。Order类仅负责业务计算(总重量、总运费),职责分离后圈复杂度降至 3。
(1)设计模式的价值
第一次题目:通过基础类设计实现业务逻辑,但代码扩展性不足,硬编码导致维护成本高。
第二次实现通过抽象类与多态将费率计算逻辑下沉到子类,符合开闭原则,新增货物类型或客户折扣时无需修改核心代码,显著提升扩展性。
单一职责原则的应用(如 Report 类独立报表生成)降低了类的复杂度,使代码结构更清晰,维护成本更低。
(2)面向对象设计的核心思想
通过封装(数据隐藏)、继承(代码复用)、多态(行为扩展)构建可维护的系统,避免过程式编程的逻辑耦合。
设计时需优先考虑职责分离,避免单一类承担过多功能(如第一次实现中 Order 类同时负责计算和输出)。
(3)编程细节的重要性
输入处理中的缓冲区管理、方法调用的作用域、异常情况的预判(如非法输入)是程序健壮性的关键,需在开发中反复测试验证。
(4)未来扩展方向
可进一步引入策略模式动态切换运费计算规则(如按距离计费),或通过单例模式管理航班池、客户池等共享资源,提升系统性能。
通过两次实现的对比,深刻体会到设计模式对代码质量的提升作用,以及面向对象设计原则在复杂业务场景中的必要性。后续开发中需更注重架构设计的前瞻性,避免过度依赖硬编码和过程式逻辑。

浙公网安备 33010602011771号