第二次blog
航空货运管理系统Blog总结
前言
两次题目集围绕航空货运管理系统的设计与迭代展开,从基础的运费计算逐步扩展至多类型业务逻辑处理,重点考察面向对象设计原则的应用能力,以及复杂业务场景下的类设计与编码实现能力。通过对比两次作业的需求变化与代码演进,深入理解了如何通过设计模式解耦业务逻辑,提升系统的可扩展性与可维护性。
知识点
第一次题目
核心功能:
计算货物的计费重量(实际重量与体积重量取较大值)。
根据货物重量分段计算基础运费(普通货物费率)。
校验订单总重量是否超过航班载重量,生成订单信息与货物明细。
关键类与设计:
Transport抽象类:定义航班公共属性(航班号、起降机场、日期、最大载重量),提供载重量校验接口(canLoad、load)。
Flight子类:继承Transport,具体化航班实体。
Cargo货物类:封装货物基本信息与计费逻辑,通过FeeCalculationStrategy接口实现运费计算解耦。
Customer客户类:存储客户基础信息(编号、姓名、电话、地址)。
Order订单类:聚合货物列表,计算总重量与总运费,管理订单相关信息。
设计原则应用:
开闭原则:通过FeeCalculationStrategy接口抽象计费策略,为后续扩展货物类型预留接口。
单一职责原则:Cargo类仅负责货物数据处理与计费计算,Order类专注于订单信息管理。
第二次题目
核心功能扩展:
新增客户类型(个人Individual/集团Corporate),实现不同折扣(个人9折、集团8折)。
新增货物类型(普通Normal/危险Dangerous/加急Expedite),每种类型对应独立计费策略。
新增支付方式(微信/支付宝/现金),支持不同支付方式的中文转换输出。
关键类与设计升级:
策略模式深化:
定义FeeCalculationStrategy接口,新增NormalFeeStrategy、DangerousFeeStrategy、ExpediteFeeStrategy实现类,分别处理不同货物的费率计算。
通过switch语句根据货物类型动态创建策略对象,注入Cargo实例。
客户类扩展:Customer类新增customerType属性,用于判断折扣类型,解耦折扣逻辑与订单处理。
订单类增强:Order类新增paymentMethod属性,通过工具方法getPaymentMethodChinese实现支付方式的中文转换。
设计原则深化:
里氏代换原则:Flight子类完全继承Transport的行为,可替换父类用于载重量校验。
合成复用原则:Order类通过聚合Cargo列表、依赖Customer和Flight对象实现功能,而非继承。
单一职责原则:支付方式处理独立为工具方法,客户类型与折扣逻辑封装在Customer类中。
题量与难度
第一次题目:
题量:需实现5个核心类(Transport、Flight、Cargo、Customer、Order),处理基础输入输出与计费逻辑。
难度:重点在于理解计费重量计算规则(体积重量公式)与分段费率逻辑,类职责划分较清晰,难度中等。
第二次题目:
题量:新增3个策略类、扩展客户类与订单类,输入项增加客户类型、货物类型、支付方式,代码量增加约40%。
难度:难点在于多策略模式的协同工作、客户折扣与支付方式的组合逻辑,需处理多条件分支与动态策略选择,复杂度较高。
设计与分析
第一次题目:基础功能实现
代码结构与核心逻辑
// 抽象运输类(里氏代换原则基础)
abstract class Transport {
protected String transportNumber;
protected double maxLoad, currentLoad; // 最大载重量、当前载重
public boolean canLoad(double weight) { // 校验是否可载重
return currentLoad + weight <= maxLoad;
}
public void load(double weight) { // 更新载重
currentLoad += weight;
}
}
// 货物类(单一职责原则)
class Cargo {
private double width, length, height, weight;
private FeeCalculationStrategy strategy; // 策略接口注入
public double getWeight() { // 计算计费重量
double volumeWeight = (width * length * height) / 6000;
return Math.max(weight, volumeWeight);
}
public double calculateFee() { // 委托策略计算运费
return strategy.calculateFee(getWeight());
}
}
// 订单类(合成复用原则)
class Order {
private List<Cargo> cargoList;
public double calculateTotalWeight() { // 计算总重量
return cargoList.stream().mapToDouble(Cargo::getWeight).sum();
}
public double calculateTotalFee() { // 计算总运费
return cargoList.stream().mapToDouble(Cargo::calculateFee).sum();
}
}
- 关系说明:
Flight继承Transport,体现里氏代换原则。Order聚合Cargo列表,Cargo依赖FeeCalculationStrategy接口,体现合成复用与依赖倒转原则。Customer与Order为关联关系,订单属于特定客户。
问题与改进
问题:
- 策略扩展性不足:仅实现普通货物策略,新增货物类型需修改
Cargo类或主逻辑。 - 输入处理耦合:
Main类直接处理输入逻辑,违反单一职责原则。
改进方向: - 分离输入处理逻辑,封装为独立的
InputService类。 - 采用工厂模式创建策略对象,避免硬编码
switch。
第二次题目:多策略与复杂业务
代码结构与核心逻辑
// 策略接口与实现类(开闭原则)
interface FeeCalculationStrategy {
double calculateFee(double weight);
}
class DangerousFeeStrategy implements FeeCalculationStrategy { // 危险货物策略
@Override
public double calculateFee(double weight) {
if (weight < 20) return 80 * weight;
// 其他重量段逻辑...
}
}
// 客户类(单一职责原则)
class Customer {
private String customerType; // Individual/Corporate
public double getDiscountRate() { // 获取折扣率
return "Corporate".equals(customerType) ? 0.8 : 0.9;
}
}
// 订单类(处理折扣与支付方式)
class Order {
private String paymentMethod;
public double calculateFinalFee(double totalFee, Customer customer) {
double discount = customer.getDiscountRate();
return totalFee * discount; // 应用折扣
}
public String getPaymentMethodCN() { // 支付方式中文转换
switch (paymentMethod) {
case "Wechat": return "微信";
// 其他分支...
}
}
}
SourceMontor报表分析 :

类图分析

关系说明:
- 新增三种策略类实现
FeeCalculationStrategy,符合开闭原则。 Customer类通过customerType属性驱动折扣逻辑,与Order协作计算最终费用。Order与支付方式解耦,通过工具方法处理输出转换。
设计原则体现
- 开闭原则:
新增货物类型时,只需实现新的FeeCalculationStrategy子类,无需修改现有计费逻辑(如Cargo类的calculateFee方法)。 - 单一职责原则:
Cargo类专注于货物数据与计费计算,Customer类仅处理客户类型与折扣,Order类负责订单信息与支付逻辑。
采坑心得
第一次题目:计费逻辑与载重量校验
场景:体积重量计算错误导致计费重量异常。
原因:输入的货物尺寸单位为厘米,但代码中误将公式写为(width + length + height) / 6000(应为乘积)。
解决方案:增加单元测试验证体积重量公式,确保volumeWeight = (width * length * height) / 6000。
场景:航班载重量校验逻辑错误,允许超重订单通过。
原因:在Main类中,transport.canLoad(totalWeight)判断顺序错误,先执行了load再校验。
解决方案:调整逻辑顺序,先校验再加载:
java if (transport.canLoad(totalWeight)) { transport.load(totalWeight); printOrderInfo(...); } else { // 输出错误信息 }
第二次题目:多策略协同与折扣计算
场景:集团客户折扣未正确应用,总费用计算错误。
原因:Order类中折扣计算逻辑写为totalFee = totalFee * discount,但totalFee未先计算基础运费。
解决方案:明确计算顺序,先计算基础运费(各货物运费总和),再应用折扣:
java double totalBaseFee = calculateTotalFee(); // 基础运费 double finalFee = totalBaseFee * customer.getDiscountRate(); // 应用折扣
场景:支付方式输入校验缺失,非法输入导致程序异常。
原因:未对paymentMethod进行枚举校验,直接使用switch处理,若输入非法值则返回空字符串。
解决方案:定义支付方式枚举类:
java enum PaymentMethod { Wechat, ALiPay, Cash } // 输入时校验合法性 PaymentMethod.valueOf(paymentMethodInput);
改进建议
策略模式优化:工厂模式解耦类型映射
现状问题:第十二周代码中通过switch语句创建策略对象,新增货物类型需修改main方法,违反开闭原则。
改进方案:引入策略工厂类:
class FeeStrategyFactory {
public static FeeCalculationStrategy createStrategy(String cargoType) {
Map<String, FeeCalculationStrategy> strategies = new HashMap<>();
strategies.put("Normal", new NormalFeeStrategy());
strategies.put("Dangerous", new DangerousFeeStrategy());
// 新增类型时只需添加映射
return strategies.getOrDefault(cargoType, null);
}
}
// 使用时
FeeCalculationStrategy strategy = FeeStrategyFactory.createStrategy(cargoType);
输入校验增强:统一参数验证
现状问题:输入项(如货物类型、客户类型)缺乏合法性校验,可能导致非法数据进入系统。
改进方案:封装校验工具类:
class InputValidator {
public static boolean isValidCustomerType(String type) {
return type.equals("Individual") || type.equals("Corporate");
}
// 其他校验方法...
}
// 在输入阶段调用
if (!InputValidator.isValidCustomerType(customerType)) {
throw new IllegalArgumentException("Invalid customer type");
}
折扣逻辑封装:客户类职责强化
现状问题:折扣计算逻辑分散在printOrderInfo方法中,与订单类耦合。
改进方案:将折扣计算移至Customer类:
class Customer {
// ...
public double applyDiscount(double totalFee) {
return totalFee * getDiscountRate();
}
}
// 在Order中调用
double finalFee = customer.applyDiscount(totalBaseFee);
日志与调试增强:记录关键流程
现状问题:调试时难以追踪货物计费重量、费率计算过程。
改进方案:在关键方法中添加日志输出:
class Cargo {
public double getWeight() {
double volumeWeight = (width * length * height) / 6000;
System.out.printf("货物%s的体积重量为%.1fkg,实际重量为%.1fkg,计费重量取%.1fkg%n",
cargoName, volumeWeight, weight, Math.max(weight, volumeWeight));
return Math.max(weight, volumeWeight);
}
}
总结
通过两次题目集的迭代开发,深入体会了面向对象设计原则在实际业务中的落地方式:
单一职责原则是类设计的基础,确保每个类专注于单一功能(如Cargo处理货物数据,Flight管理航班载重量),降低复杂度。
开闭原则通过策略模式实现,允许在不修改现有代码的前提下扩展新货物类型或计费规则,提升系统可扩展性。
里氏代换原则通过抽象类与子类的继承关系(Flight继承Transport),确保子类可无缝替换父类,增强代码复用性。
在编码过程中,从最初的“功能优先”逐步转向“设计优先”,学会了通过类拆分、接口抽象和模式应用来应对需求变化。
然而,设计的完善是一个持续过程。当前代码在输入校验、工厂模式应用等方面仍有优化空间,后续可进一步引入枚举类、反射机制等提升代码健壮性与可维护性。



浙公网安备 33010602011771号