第二次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等工具提升代码质量。

课程建议

增加实战案例:通过电商、物流等真实项目案例讲解设计模式。

强化代码评审:通过小组互评发现设计缺陷,提升代码规范性。

posted @ 2025-05-25 23:43  新欢远胜旧爱  阅读(15)  评论(1)    收藏  举报