(1)前言
第一次迭代核心任务是实现空运费计算的基础逻辑(计费重量、分段费率)与订单流程。通过单一职责原则将客户、货物、航班、订单等功能拆分至独立类,例如Cargo类仅负责计算体积重量和计费重量,Flight类专注于载重校验,避免功能混杂。未修改原有类结构,仅通过新增子类完成功能扩展,业务逻辑较简单,但需初次设计类间关系。
第二次迭代引入客户类型折扣(个人 / 集团用户)和货物类型费率(普通 / 危险 / 加急),大幅增加了复杂度。设计重点转向依赖倒转原则,通过抽象类CustomerType和CargoType定义接口(如getDiscountRate()、getRate()),具体类型(如IndividualCustomer、ExpediteCargo)实现接口,使高层模块(Order类)依赖抽象而非具体类。需要重构原有代码以适配抽象层,处理多维度变化(客户 + 货物 + 支付),对设计原则的综合运用要求更高,代码结构更灵活但复杂度显著增加。
两次迭代体现了面向对象设计从 “功能实现” 到 “可维护性架构” 的演进:首次通过四大原则建立清晰的类职责边界,第二次以依赖倒转原则为核心,构建可扩展的抽象体系,应对业务变化。通过设计原则降低耦合度,使系统在需求扩展(如新增货物类型、折扣策略)时具备弹性。越到后面我越发现这些原则像搭房子的钢筋,看着限制多,却能让系统稳稳当当经得起需求变化。以下是对三次迭代的具体分析:
第一次迭代
题目
航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明如下。
某航空公司“航空货运管理系统”中的空运费的计算涉及多个因素,通常包 括货物重量/体积、运输距离、附加费用、货物类型、客户类型以及市场供需等。 本次作业主要考虑货物重量/体积,以下是具体的计算方式和关键要点:
一、计费重量的确定 空运以实际重量(GrossWeight)和体积重量(VolumeWeight)中的较 高者作为计费重量。 计算公式: 体积重量(kg)= 货物体积(长×宽×高,单位:厘米)÷6000 示例: 若货物实际重量为80kg,体积为120cm×80cm×60cm,则: 体积重量 =(120×80×60)÷6000=96kg 计费重量取96kg(因96kg>80kg)。
二、基础运费计算 费率(Rate):航空公司或货代根据航线、货物类型、市场行情等制定(如 CNY 30/kg)。本次作业费率采用分段计算方式。
输入格式:
按如下顺序分别输入客户信息、货物信息、航班信息以及订单信息。
客户编号
客户姓名
客户电话
客户地址
运送货物数量
货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为YYYY-MM-DD)
航班最大载重量
订单编号
订单日期(格式为YYYY-MM-DD)
发件人地址
发件人姓名
发件人电话
收件人地址
收件人姓名
收件人电话
输出格式:
如果订单中货物重量超过航班剩余载重量,程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order. ,程序终止运行。
如果航班载重量可以承接该订单,输出如下:
客户:姓名(电话)订单信息如下:
航班号:
订单号:
订单日期:
发件人姓名:
发件人电话:
发件人地址:
收件人姓名:
收件人电话:
收件人地址:
订单总重量(kg):
微信支付金额:
货物明细如下:
明细编号 货物名称 计费重量 计费费率 应交运费
1 ...
2 ...
注:输出中实型数均保留1位小数。
输入样例:
在这里给出一组输入。例如:
10001
郭靖
13807911234
南昌航空大学
2
101
发电机
80
60
40
80
102
信号发生器
55
70
60
45
MU1234
昌北国际机场
大兴国际机场
2025-04-22
1000
900001
2025-04-22
南昌大学
洪七公
18907912325
北京大学
黄药师
13607912546
输出样例:
在这里给出相应的输出。例如:
客户:郭靖(13807911234)订单信息如下:
航班号:MU1234
订单号:900001
订单日期:2025-04-22
发件人姓名:洪七公
发件人电话:18907912325
发件人地址:南昌大学
收件人姓名:黄药师
收件人电话:13607912546
收件人地址:北京大学
订单总重量(kg):125.0
微信支付金额:3350.0
货物明细如下:
明细编号 货物名称 计费重量 计费费率 应交运费
1 发电机 80.0 25.0 2000.0
2 信号发生器 45.0 30.0 1350.0
知识点:1.面向对象基础:类的定义、属性与方法,对象的创建与使用。
2.单一职责原则:确保每个类只负责一个特定功能。
3.里氏代换原则:子类能够替换父类且功能正常。
4.开闭原则:对扩展开放,对修改关闭。
5.合成复用原则:优先使用组合而非继承实现复用。
6.基础算法:计费重量计算、基础运费计算。
题量:需实现 5-7 个核心类,约 20-30 个方法。
输入处理逻辑较简单,输出格式固定。
难度:中等。需合理设计类结构,遵循设计原则,但业务逻辑较单一。
用到的类和方法:
1.Recipient(收件人)
属性:地址、姓名、电话
方法:getAddress()、getName()、getPhone()(获取信息)
2.Sender(发件人)
属性:地址、姓名、电话
方法:getAddress()、getName()、getPhone()(获取信息)
3.Goods(货物)
属性:编号、名称、长宽高、实际重量、计费重量
方法:
calculateBillingWeight():计算体积重量并取较大值作为计费重量
getBillingWeight():获取计费重量(其他为基础 getter)
4.Flight(航班)
属性:航班号、起降机场、日期、最大载重、当前载重
方法:
canCarry(double weight):检查是否能承载订单重量
addLoad(double weight):更新当前载重
5.Client(客户)
属性:编号、姓名、电话、地址
方法:getName()、getPhone()(仅暴露必要信息)
6.Order(订单)
属性:订单号、日期、发件人、收件人、货物列表、运费计算器
方法:
getTotalWeight():计算订单总重量(累加货物计费重量)
getTotalFreight():计算总运费(调用 FreightCalculator)
FreightCalculator(运费计算器)
方法:calculateFreight(double weight):根据重量分段计算基础运费
7.Main(主类)
方法:
main:处理输入逻辑、创建对象、校验载重、输出结果
getRate(double weight):辅助获取费率(与 FreightCalculator 逻辑重复)
第二次迭代
题目
航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明参看说明文件。
“航空货运管理系统”题目说明(续)
(OO课程组 2025.05)
某航空公司“航空货运管理系统”中的空运费的计算涉及多个因素,通常包
括货物重量/体积、运输距离、附加费用、货物类型、客户类型以及市场供需等。
本次作业主要考虑货物重量/体积,以下是具体的计算方式和关键要点:
一、计费重量的确定
空运以实际重量(GrossWeight)和体积重量(VolumeWeight)中的较
高者作为计费重量。
计算公式:
体积重量(kg)= 货物体积(长×宽×高,单位:厘米)÷6000
示例:
若货物实际重量为80kg,体积为120cm×80cm×60cm,则:
体积重量 =(120×80×60)÷6000=96kg
计费重量取96kg(因96kg>80kg)。
二、基础运费计算
1
费率(Rate):航空公司或货代根据航线、货物类型、市场行情等制定(如
CNY30/kg)。本次作业费率与货物类型有关,货物类型分为普通货物、危险货
物和加急货物三种,其费率分别为:
计算公式:基础运费 = 计费重量 × 费率 × 折扣率
其中,折扣率是指不同的用户类型针对每个订单的运费可以享受相应的折扣,
在本题中,用户分为个人用户和集团用户,其中个人用户可享受订单运费的9
折优惠,集团用户可享受订单运费的8折优惠。
三、题目说明
本次题目模拟某客户到该航空公司办理一次货运业务的过程:
航空公司提供如下信息:
航班信息(航班号,航班起飞机场,航班降落机场,航班日期,航班最大载
重量)
2
客户填写货运订单并进行支付,需要提供如下信息:
客户信息(姓名,电话号码等)
货物信息(货物名称,货物包装长、宽、高尺寸,货物重量等)
运送信息(发件人姓名、电话、地址,收件人姓名、电话、地址,所选
航班号,订单日期)
支付方式(支付宝支付、微信支付、现金支付)
注:一个货运订单可以运送多件货物,每件货物均需要根据重量及费率单独
计费。
程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信
息报表及货物明细报表。
四、题目要求
本次题目重点考核面向对象设计原则中的单一职责原则、里氏代换原则、开
闭原则以及合成复用原则、依赖倒转原则,除需要在PTA平台提交源码外,还
需要在超星平台提交本次作业最终得分源码(首次提交最高分源码)的类图,
评判标准为:
基础得分:PTA实际得分
设计因素:单一职责原则(20%)、里氏代换原则(20%)、开闭原则(20%)、
合成复用原则(20%)、依赖倒转原则(20%)。
输入格式:
按如下顺序分别输入客户信息、货物信息、航班信息以及订单信息。
客户类型[可输入项:Individual/Corporate]
客户编号
客户姓名
客户电话
客户地址
货物类型[可输入项:Normal/Expedite/Dangerous]
运送货物数量
[货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为YYYY-MM-DD)
航班最大载重量
订单编号
订单日期(格式为YYYY-MM-DD)
发件人地址
发件人姓名
发件人电话
收件人地址
收件人姓名
收件人电话
支付方式[可输入项:Wechat/ALiPay/Cash]
输出格式:
如果订单中货物重量超过航班剩余载重量,程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order. ,程序终止运行。
如果航班载重量可以承接该订单,输出如下:
客户:姓名(电话)订单信息如下:
航班号:
订单号:
订单日期:
发件人姓名:
发件人电话:
发件人地址:
收件人姓名:
收件人电话:
收件人地址:
订单总重量(kg):
[微信/支付宝/现金]支付金额:
货物明细如下:
明细编号 货物名称 计费重量 计费费率 应交运费
1 ...
2 ...
注:输出中实型数均保留1位小数。
输入样例:
在这里给出一组输入。例如:
Corporate
10001
郭靖
13807911234
南昌航空大学
Expedite
2
101
发电机
80
60
40
80
102
信号发生器
55
70
60
45
MU1234
昌北国际机场
大兴国际机场
2025-04-22
1000
900001
2025-04-22
南昌大学
洪七公
18907912325
北京大学
黄药师
13607912546
ALiPay
输出样例:
在这里给出相应的输出。例如:
客户:郭靖(13807911234)订单信息如下:
航班号:MU1234
订单号:900001
订单日期:2025-04-22
发件人姓名:洪七公
发件人电话:18907912325
发件人地址:南昌大学
收件人姓名:黄药师
收件人电话:13607912546
收件人地址:北京大学
订单总重量(kg):125.0
支付宝支付金额:4360.0
货物明细如下:
明细编号 货物名称 计费重量 计费费率 应交运费
1 发电机 80.0 40.0 3200.0
2 信号发生器 45.0 50.0 2250.0
知识点:强调单一职责原则(SRP)的应用,将不同的功能模块拆分成不同的类,如乘客请求类、队列类、控制类等,以提高代码的可维护性和可扩展性。同时,需要处理无效请求和重复请求。
题量:新增 3-5 个类,修改原有类的方法。
难度: 较高。需重构原有代码以适应新需求,严格遵循依赖倒转原则,处理多维度的变化点。
用到的类和方法:
1. Recipient 类(收件人)
属性:
private String address;(地址)
private String name;(姓名)
private String phone;(电话)
方法:
public Recipient(String address, String name, String phone)(构造方法)
public String getAddress()(获取地址)
public String getName()(获取姓名)
public String getPhone()(获取电话)
2. Sender 类(发件人)
属性:
private String address;(地址)
private String name;(姓名)
private String phone;(电话)
方法:
public Sender(String address, String name, String phone)(构造方法)
public String getAddress()(获取地址)
public String getName()(获取姓名)
public String getPhone()(获取电话)
3. Goods 类(货物)
属性:
private int num;(编号)
private String name;(名称)
private double width/length/height;(尺寸)
private double weight;(实际重量)
private double billingWeight;(计费重量)
private String goodsType;(货物类型,新增)
方法:
public Goods(int num, String name, double width, double length, double height, double weight, String goodsType)(构造方法,新增 goodsType 参数)
public int getNum()(获取编号)
public String getName()(获取名称)
public double getWidth()/getLength()/getHeight()/getWeight()(获取尺寸和重量)
public double getBillingWeight()(获取计费重量)
public String getGoodsType()(获取货物类型,新增)
private double calculateBillingWeight()(计算计费重量,体积重量与实际重量取较大值)
4. Flight类(航班)
private String num;(航班号)
private String beginFlight/endFlight;(起降机场)
private String time;(日期)
private double maxload;(最大载重)
private double currentLoad;(当前载重)
方法:
public Flight(String num, String beginFlight, String endFlight, String time, double maxload)(构造方法)
public String getNum()(获取航班号)
public double getMaxload()(获取最大载重)
public double getCurrentLoad()(获取当前载重)
public boolean canCarry(double weight)(检查是否可承载重量)
public void addLoad(double weight)(更新当前载重)
public String getTime()(获取日期)
5. Order 类(订单)
属性:
private int num;(订单号)
private String time;(日期)
private Sender sender;(发件人)
private Recipient recipient;(收件人)
private Goods[] goods;(货物列表)
private FreightCalculator freightCalculator;(运费计算器)
private String paymentMethod;(支付方式,新增)
private String clientType;(客户类型,新增)
方法:
public Order(int num, String time, Sender sender, Recipient recipient, Goods[] goods, FreightCalculator freightCalculator, String paymentMethod, String clientType)(构造方法,新增支付方式和客户类型参数)
public int getNum()(获取订单号)
public String getTime()(获取日期)
public Sender getSender()(获取发件人)
public Recipient getRecipient()(获取收件人)
public Goods[] getGoods()(获取货物列表)
public double getTotalWeight()(计算总重量:累加货物计费重量)
public double getTotalFreight()(计算总运费:
调用 FreightCalculator 计算单件运费
根据客户类型(clientType)应用折扣:集团 8 折,个人 9 折)
public String getPaymentMethod()(获取支付方式)
6. FreightCalculator 类(运费计算器)
方法:
public double calculateFreight(double weight, String goodsType)(计算单件运费:
根据货物类型(Normal/Expedite/Dangerous)和重量分段确定费率
返回 重量 × 费率)
7. Main 类(主类)
方法:
public static void main(String[] args)(主逻辑):
输入处理:客户类型、客户信息、货物类型、货物信息、航班信息、订单信息、支付方式
创建对象并校验航班载重
输出订单信息和货物明细(包含支付方式转换和折扣后的总金额)
private static double getRate(double weight, String goodsType)(辅助方法:根据货物类型和重量获取费率)
(2)设计与分析
系统设计整体思路
- 需求理解
核心功能:航空货运订单管理,计算运费并生成报表。
关键因素:计费重量(实际重量 vs 体积重量)、货物类型、客户类型折扣、支付方式。
扩展点:未来可能新增货物类型、客户类型或支付方式。 - 面向对象设计原则应用
单一职责原则
将系统拆分为独立类:客户管理、货物计算、航班校验、订单管理。
示例:Goods 类仅负责计算计费重量,Flight 类仅校验载重。
开闭原则
通过抽象类 / 接口隔离变化点(如货物类型、客户类型)。
新增类型时,只需实现接口而不修改现有代码。
依赖倒转原则
高层模块(如 Order)依赖抽象(如 CustomerType 接口),而非具体实现。
里氏代换原则
子类(如 CorporateCustomer)可替换父类(CustomerType)而不影响功能。
合成复用原则
通过组合(如 Order 包含 Goods[])而非继承实现功能复用。
算法思路 - 计费重量计算
体积重量 = (长 × 宽 × 高) ÷ 6000(单位:kg)
计费重量 = max(实际重量, 体积重量)
基础运费计算
第一次迭代(仅重量分段)
运费 = 计费重量 × 费率
其中,费率根据重量范围动态调整:
重量 < 20kg:35元/kg
20kg ≤ 重量 < 50kg:30元/kg
50kg ≤ 重量 < 100kg:25元/kg
重量 ≥ 100kg:15元/kg
第二次迭代(重量分段 + 货物类型)
运费 = 计费重量 × 费率 × 折扣率
其中,费率由货物类型决定:
普通货物(Normal):同上分段费率
加急货物(Expedite):更高的分段费率
危险货物(Dangerous):特殊分段费率
折扣率由客户类型决定:
个人用户(Individual):9折
集团用户(Corporate):8折
第一次迭代代码分析





符合单一职责原则,各实体类(Client、Goods、Flight 等)职责清晰,仅处理自身相关属性和行为。例如,Goods 类专注于计算计费重量,Flight 类负责载重校验。
符合合成复用原则Order 类通过组合 Goods、Sender、Recipient 对象实现功能,而非继承。
存在基础多态应用,通过 FreightCalculator 接口隔离运费计算逻辑,支持未来扩展不同计费策略。
设计缺陷
违反开闭原则,若新增货物类型或计费规则,需直接修改 FreightCalculator 类,不符合 “对扩展开放,对修改关闭”。
逻辑重复。Main 类中的 getRate() 方法与 FreightCalculator 逻辑重复,违背单一职责。
缺乏抽象层。未针对客户类型、支付方式等设计抽象接口,难以扩展新类型(如企业客户、现金支付)。
关键代码问题
java
// 运费计算逻辑硬编码在一个方法中,扩展性差
public double calculateFreight(double weight) {
if (weight < 20) return weight * 35;
else if (weight < 50) return weight * 30;
// ...
}
// Main 类中的重复逻辑
private static double getRate(double weight) {
// 与 FreightCalculator 中逻辑完全相同
}
第二次迭代代码分析






设计优化
实现了功能扩展,支持客户类型折扣(个人 / 集团)和货物类型费率(普通 / 加急 / 危险)。通过 clientType 和 goodsType 参数动态调整运费计算,增强灵活性。
设计缺陷
直接通过字符串(如 "Corporate"、"Expedite")判断客户类型和货物类型,依赖具体实现而非抽象。合成复用不足,Order 类未通过组合抽象客户类型和货物类型,而是通过字符串硬编码逻辑。
可以进行改进:
java
// 定义抽象接口
interface CustomerType { double getDiscountRate(); }
class CorporateCustomer implements CustomerType { ... }
class IndividualCustomer implements CustomerType { ... }
关键代码问题
java
// 货物类型判断逻辑分散且重复
public double calculateFreight(double weight, String goodsType) {
if ("Normal".equals(goodsType)) {
// 多层嵌套条件,代码臃肿
} else if ("Expedite".equals(goodsType)) {
// ...
}
}
// Order 类中的客户折扣逻辑
public double getTotalFreight() {
if ("Corporate".equals(clientType)) {
total *= 0.8;
} else if ("Individual".equals(clientType)) {
total *= 0.9;
}
}
(3)采坑心得
刚写完代码的时候被兴奋冲昏了头脑,忘记题目要求的输出总重量是计费重量了,而我的代码实现的输出实际重量。因此运行结果一直是答案错误,卡了好久T-T后来问同学才恍然大悟。
不过踩过最痛的坑是设计原则的理解偏差与代码重构的权衡。首次迭代时,为了快速实现功能,我直接在FreightCalculator中硬编码重量分段逻辑,还在Main类里复制了相同的费率计算方法,完全没意识到这违背了单一职责原则。当第二次迭代需要新增货物类型和客户折扣时,不得不面对满是if-else的 “面条代码”,甚至要在Order类中用字符串判断客户类型,代码变得异常难看。
另一个大坑是对依赖倒转原则的忽视。我错误地用字符串(如"Corporate")直接控制业务逻辑,而不是通过抽象接口。这导致新增 “VIP 客户” 时,必须修改所有涉及客户类型判断的代码,违反了开闭原则。直到代码难以维护时,才意识到应该先定义CustomerType接口,让具体客户类实现折扣逻辑,这样高层模块(如Order)只需依赖接口,而非具体字符串。
此外,输入处理的细节也让我栽了跟头。第一次迭代中,忘记处理nextInt()后的换行符,导致nextLine()读取空值,程序直接崩溃,给我报了好多次类型不匹配的错误。
总结来看,最大的教训是:面向对象设计不能只关注功能实现,更要提前为变化留好 “扩展点”。虽然初期会增加设计成本,但能避免后期重构的 “血崩”。写代码时多问自己:“如果明天需求变了,这段代码要改多少处?”,或许能提前避开许多坑。以下是具体描述:
-
硬编码与逻辑重复
问题描述:
在FreightCalculator类中直接硬编码重量分段逻辑,且在Main类中重复实现相同的费率计算方法,导致代码冗余。
解决办法:
将费率计算逻辑完全封装到FreightCalculator类中,移除Main类中的重复代码。
使用策略模式,将不同货物类型的费率计算封装为独立策略类,通过接口调用。 -
输入处理异常
问题描述:忘记处理nextInt()后的换行符
解决方法:
统一输入处理流程:在读取数值型输入(如nextInt())后,立即用scanner.nextLine()消耗残留的换行符,避免影响后续字符串输入。
3.输出答案错误
问题描述:错误地返回了实际重量
解决方法:
修改代码,使其返回计费重量 -
依赖具体实现而非抽象
问题描述:
在Order类中通过字符串(如"Corporate")判断客户类型,直接依赖具体实现,违背依赖倒转原则。
解决办法:
抽象客户类型为CustomerType接口,具体客户类(如CorporateCustomer)实现该接口。
在Order类中依赖CustomerType接口,而非具体客户类,通过构造函数注入具体实现。
(4)改进建议
一、设计原则改进
- 依赖倒转原则
问题:通过字符串(如"Corporate")直接判断客户类型和货物类型,违背依赖抽象的原则。
解决方案:
java
// 定义客户类型抽象接口
interface CustomerType {
double getDiscountRate();
}
// 具体实现类
class CorporateCustomer implements CustomerType {
@Override
public double getDiscountRate() { return 0.8; }
}
// 订单类依赖抽象而非具体类
class Order {
private CustomerType customerType;
public Order(CustomerType customerType, ...) {
this.customerType = customerType;
}
public double getTotalFreight() {
return rawFreight * customerType.getDiscountRate(); // 多态调用
}
}
二、代码结构优化
- 分离关注点
问题:Main类承担过多职责(输入处理、业务逻辑、输出展示)。
解决方案:
java
// 输入处理器
class InputHandler {
public static Order createOrderFromInput(Scanner scanner) {
// 处理输入逻辑,返回订单对象
}
}
// 输出格式化器
class OutputFormatter {
public static void printOrderReport(Order order) {
// 生成并打印订单报表
}
}
// Main类仅负责流程协调
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Order order = InputHandler.createOrderFromInput(scanner);
OutputFormatter.printOrderReport(order);
scanner.close();
}
- 统一异常处理
问题:输入异常(如非数字重量)导致程序崩溃。
解决方案:
java
class InputHandler {
public static double readPositiveDouble(Scanner scanner, String prompt) {
while (true) {
System.out.print(prompt);
try {
double value = scanner.nextDouble();
if (value > 0) return value;
System.out.println("请输入正数!");
} catch (InputMismatchException e) {
System.out.println("请输入合法数值!");
scanner.nextLine(); // 清除错误输入
}
}
}
}
三、算法优化
-
简化运费计算逻辑
问题:FreightCalculator中嵌套多层if-else,代码冗长。
解决方案:
java
// 使用策略模式替代条件判断
class FreightCalculator {
public double calculateFreight(Goods goods) {
CargoType cargoType = goods.getCargoType();
return goods.getBillingWeight() * cargoType.calculateRate(goods.getBillingWeight());
}
} -
航班载重校验
问题:载重校验分散在Main类和Flight类中。
解决方案:
java
class Flight {
public boolean canCarry(Order order) {
return getCurrentLoad() + order.getTotalWeight() <= getMaxload();
}
}
// 在订单创建时校验
class OrderService {
public void validateOrder(Order order, Flight flight) {
if (!flight.canCarry(order)) {
throw new IllegalArgumentException("航班载重不足");
}
}
}
四、输入输出优化
-
输入校验增强
问题:未校验用户输入的枚举值(如支付方式)。
解决方案:
java
class InputValidator {
public static boolean isValidPaymentMethod(String method) {
return Set.of("Wechat", "ALiPay", "Cash").contains(method);
}
} -
输出格式统一
问题:支付方式显示硬编码(如"微信支付")。
解决方案:
java
enum PaymentMethod {
WECHAT("微信"), ALIPAY("支付宝"), CASH("现金");private final String displayName;
PaymentMethod(String displayName) {
this.displayName = displayName;
}public String getDisplayName() {
return displayName;
}
}
五、性能与可维护性优化
使用枚举替代字符串判断
java
enum CargoTypeEnum {
NORMAL, EXPEDITE, DANGEROUS;
}
添加注释与文档
通过以上可以增强代码的可扩展性,可维护性,健壮性,和可测试性。
(5)总结
两次迭代从基础功能搭建(第一次迭代实现计费重量与分段运费)到复杂业务扩展(第二次迭代支持客户折扣与货物类型费率),我初步了解了航空货运管理系统的核心逻辑。设通过拆分独立类(如Goods、Flight)实现单一职责,利用接口(如支付方式)体现里氏代换原则,并通过参数化设计(如clientType、goodsType)应对业务变化。代码基本实现了订单流程管理、运费计算及报表生成功能,满足题目要求。但是设计原则应用不彻底,客户类型和货物类型仍通过字符串判断,未完全基于抽象接口实现多态,违背依赖倒转原则,导致新增类型时需修改核心类。业务逻辑(如运费计算)与输入输出逻辑(Main类)混杂,耦合度高,维护成本大。
这次迭代是面向对象设计从理论到落地的尝试,未来我会更注重 “设计先行”,在需求分析阶段识别变化点,提前构建抽象层,避免后期被动重构。
浙公网安备 33010602011771号