第二次Blog作业
一、前言
在近期的两次题目集(题目集8和题目集9)中,我们围绕“航空货运管理系统”进行了两次迭代开发,从基础功能实现到复杂业务逻辑扩展,逐步深入面向对象设计的核心思想。以下从知识点、题量及难度三个维度进行总结:
知识点覆盖
题目集8:
基础类设计:通过Customer、Cargo、Flight、Order等类的定义,掌握单一职责原则(SRP)。
数据封装:使用私有成员变量与公共访问方法实现数据隐藏。
简单运费计算:基于实际重量与体积重量的计费逻辑实现。
输入输出处理:通过Scanner类实现命令行数据的动态读取与格式化输出。
题目集9:
继承与多态:通过抽象类Cargo派生出NormalCargo、ExpediteCargo等子类,体现开闭原则(OCP)。
策略模式应用:不同支付方式(微信、支付宝)的折扣逻辑通过条件分支实现。
复杂运费规则:结合货物类型与客户类型动态计算运费,引入分层设计思想。
题量与难度
题量:两次题目均围绕同一系统展开,题目集8侧重基础功能实现,题目集9侧重扩展与重构,功能模块逐步增加。
难度对比:
题目集8(中等):需处理多类数据交互,但逻辑较直接,适合巩固类设计与基础算法。
题目集9(较高):需重构代码以支持继承与多态,并实现动态业务规则(如折扣、货物类型),考验设计能力。
二、设计与分析
题目集8设计分析
核心需求:实现货运订单的创建、载重校验及运费计算。
类结构与职责
Customer类:存储客户基本信息(姓名、电话),无复杂逻辑。
Cargo类:核心计费模块,包含计费重量计算(getChargeableWeight)及分段费率(getRate)。
Flight类:管理航班载重,提供载重校验方法(canAddOrder)。
Order类:聚合客户、货物及航班信息,输出订单详情。
关键代码分析
计费逻辑实现:
java
public double getChargeableWeight() {
return Math.max(weight, (width * length * height) / 6000);
}
通过直接计算体积重量与实际重量的最大值,逻辑简洁但缺乏扩展性。
分段费率设计:
java
public double getRate() {
double cw = getChargeableWeight();
if (cw < 20) return 35.0;
else if (cw < 50) return 30.0;
// ...
}
硬编码费率规则,违反开放封闭原则(新增费率需修改源码)。
类图与结构缺陷
plaintext
+----------------+ +----------------+
| Order | | Cargo |
+----------------+ +----------------+
| - customer |<>------| - id |
| - flight | | - name |
| - cargos | | - width |
+----------------+ | - length |
| - height |
+----------------+
问题:Cargo类承担过多职责(计费规则与数据存储耦合),导致后续扩展困难。
题目集9设计分析
核心需求:在题目集8基础上支持货物类型、支付方式及客户类型的影响。
改进设计
继承与多态:
java
abstract class Cargo {
public abstract double getRate();
}
class NormalCargo extends Cargo {
@Override
public double getRate() { return 30; }
}
通过抽象类分离货物类型与费率规则,支持未来新增货物类型。
支付策略实现:
java
public double getPaymentAmount() {
switch (paymentMethod) {
case "Wechat": return total * 0.9;
case "ALiPay": return total * 0.8;
}
}
虽未完全实现策略模式,但通过条件分支实现动态折扣计算。
类图优化
plaintext
+----------------+ +----------------+
| Order | | Cargo |
+----------------+ +----------------+
| - customer |<>------| <
| - cargos | +----------------+
| - flight | | +getRate() |
+----------------+ +----------------+
^ ^ ^
/ | \
+-------------+ +----------+ +-------------+
| NormalCargo | |Expedite | |Dangerous |
+-------------+ |Cargo | |Cargo |
| +getRate() | +----------+ +-------------+
+-------------+ | +getRate()| | +getRate() |
+----------+ +-------------+
优势:通过继承实现多态,符合开闭原则;Cargo类的职责单一化。
复杂度分析
方法圈复杂度:题目集8中Cargo.getRate()方法的圈复杂度为4(多个if-else分支),题目集9中通过多态降低至1。
类耦合度:题目集9中Order类依赖抽象Cargo,耦合度降低,模块独立性增强。
三、采坑心得
输入处理问题
问题描述:在题目集8中,未对输入格式(如日期、数字)进行校验,导致非法输入时程序崩溃。
测试用例失败:当输入非数字字符时,Scanner.nextDouble()抛出InputMismatchException,但代码未捕获异常。
解决方案:在题目集9中增加异常处理:
java
try {
double weight = scanner.nextDouble();
} catch (InputMismatchException e) {
System.out.println("输入必须为数字");
scanner.nextLine(); // 清空无效输入
}
继承设计缺陷
问题描述:题目集9中未将Customer类按类型(个人/集团)分层,导致折扣逻辑与Order类强耦合。
代码重复:若新增客户类型,需修改getPaymentAmount()方法,违反开闭原则。
改进方案:将客户类型抽象为父类,子类实现折扣计算:
java
abstract class Customer {
public abstract double applyDiscount(double amount);
}
class IndividualCustomer extends Customer {
@Override
public double applyDiscount(double amount) { return amount * 0.9; }
}
排序逻辑缺失
问题描述:题目集8中货物明细未按计费重量排序,输出顺序混乱。
测试结果:当输入多件货物时,输出顺序与输入顺序一致,不符合业务需求。
解决方案:在题目集9中引入排序:
java
cargos.sort((c1, c2) -> Double.compare(c2.getChargeWeight(), c1.getChargeWeight()));
四、改进建议
引入设计模式
策略模式:将支付折扣逻辑封装为独立策略类。
java
interface PaymentStrategy {
double applyDiscount(double amount);
}
class WechatStrategy implements PaymentStrategy {
@Override
public double applyDiscount(double amount) { return amount * 0.9; }
}
工厂模式:通过工厂类创建Cargo对象,避免switch-case。
java
class CargoFactory {
public static Cargo createCargo(String type, String id, ...) {
return switch (type) {
case "Normal" -> new NormalCargo(id, ...);
case "Expedite" -> new ExpediteCargo(id, ...);
default -> throw new IllegalArgumentException("无效货物类型");
};
}
}
增强输入验证
正则表达式校验:对日期、电话等字段进行格式验证。
java
if (!orderDate.matches("\d{4}-\d{2}-\d{2}")) {
throw new IllegalArgumentException("日期格式错误");
}
单元测试覆盖
JUnit测试用例:针对核心逻辑编写测试代码。
java
@Test
void testExpediteCargoRate() {
Cargo cargo = new ExpediteCargo("E1", "药品", 50, 50, 50, 10);
assertEquals(40, cargo.getRate());
}
五、总结
学习成果
面向对象设计能力:通过两次迭代,掌握了类设计、继承与多态的应用。
代码重构意识:认识到高内聚低耦合的重要性,学会通过抽象分离变与不变。
异常处理经验:理解输入校验与异常捕获对程序健壮性的影响。
待改进方向
设计模式深入:需进一步掌握工厂、策略等模式的实际应用场景。
测试驱动开发:缺乏单元测试习惯,需学习JUnit等工具提升代码质量。
课程建议
增加实战案例:通过电商、物流等真实项目案例讲解设计模式。
强化代码评审:通过小组互评发现设计缺陷,提升代码规范性。
浙公网安备 33010602011771号