题目集8~9总结性Blog
前言
题目集8和9重点围绕“航空货运管理系统”展开,聚焦面向对象设计原则的应用。两次作业的知识点涵盖类设计、继承与多态、接口实现、输入输出处理,并逐步引入设计模式思想。
题量适中但难度递进:题目集8要求基础类建模;题目集9需重构代码以支持多类型货物和支付方式,复杂度显著提高。
通过这两次作业,我深入理解了高内聚低耦合的设计目标,并实践了通过多态和策略模式应对需求变化。
第一次作业
作业要求
本次题目模拟某客户到该航空公司办理一次货运业务的过程:
航空公司提供如下信息:
航班信息(航班号,航班起飞机场所在城市,航班降落机场所在城市,航班
日期,航班最大载重量)
客户填写货运订单并进行支付,需要提供如下信息:
客户信息(姓名,电话号码等)
货物信息(货物名称,货物包装长、宽、高尺寸,货物重量等)
运送信息(发件人姓名、电话、地址,收件人姓名、电话、地址,所选
航班号,订单日期)
支付方式(支付宝支付、微信支付)
注:一个货运订单可以运送多件货物,每件货物均需要根据重量及费率单独
计费。
程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信
息报表及货物明细报表。
核心需求
实现货物重量计算、运费阶梯费率、航班载重校验及订单信息输出
实现方法
1.输入解析:按固定顺序逐行读取输入,依次构造客户、货物、航班、订单等对象。
2.对象构建:通过构造函数整合数据为业务对象。
3.运费计算: 根据计费重量匹配RateCalculator;
4.载重验证:对比订单总重量与航班最大载重,超限则报错终止。
5.输出生成:按固定模板输出客户、航班、订单信息及总金额;
货物明细表:遍历货物列表,输出名称、计费重量、费率、运费,制表符对齐。
代码规模
第一次作业代码规模如下图。

类图
第一次作业类图如下:

Main:程序入口,协调流程,创建对象。
Cargo:货物数据存储和计费计算。
Order:订单管理,聚合货物和客户信息,计算总费用。
Flight:航班信息及载重验证。
Customer:客户信息存储。
RateCalculator:费率计算策略。
ICargo:统一货物接口,确保多态。
复杂度分析
第一次作业的复杂度分析如下。

代码复杂度暴露以下几个问题:
RateCalculator.calculateRate()的分支过多,维护困难。
Main类臃肿:输入解析、业务逻辑、输出展示耦合。
扩展性差:新增货物类型需修改RateCalculator,违反开闭原则。
Bug分析
1.输入处理可能越界
问题分析:若订单发件人信息不应重复输入,代码会多读取行,导致index越界。
2.客户信息与发件人信息输出不一致
问题分析:输出中的客户信息来自客户基本信息,而发件人信息来自其他输入,导致两者可能不一致。
改进建议
输入验证:增加对输入数据的有效性检查(如非负数、日期格式)。
客户信息整合:使用主客户信息作为发件人,避免重复输入。
异常处理:添加try-catch块处理解析错误(如非数字输入)。
代码解耦:将输入解析和业务逻辑分离,提高可维护性。
第二次作业
作业要求
在第一次作业的基础上,货物类型分为普通货物、危险货物和加急货物三种,且每种货物的费率不同。
客户类型分为两类:Individual/Corporate,对应不同的折扣率。
支付方式分为支付宝支付、微信支付、现金支付三类。
此外代码细节上需要符合:单一职责原则、里氏代换原则、开闭原则、合成复用原则、依赖倒转原则。
实现方法
1.输入解析:分模块逐层解析
步骤:
客户模块:读取客户类型(企业/个人)→ 构造Customer对象(ID、姓名、电话、地址)。
货物模块:读取货物类型(普通/危险/加急)→ 创建对应RateCalculator → 循环解析每个货物的名称、尺寸、重量,构建Cargo列表。
航班模块:读取航班号、起降地、日期、最大载重 → 构建Flight对象。
订单模块:读取订单号、日期、发/收件人信息、支付方式 → 构造OrderDetails对象。
2. 对象构建:组合业务对象树
核心对象:
Cargo:绑定RateCalculator,根据货物类型动态计算费率。
Order:聚合发件人、收件人、货物列表,提供总重量和总运费接口。
Flight:承载订单的运输约束(最大载重)。
构建逻辑:
Cargo:通过尺寸和重量计算体积重量,与实际重量比较得出计费重量。
RateCalculator:根据货物类型定义阶梯费率规则(如危险品费率更高)。
3. 运费计算:分层递进计算
计算流程:
单个货物费用:Cargo.getFee() = 计费重量 × 阶梯费率(由RateCalculator提供)。
总运费:Order.getTotalFee() = 所有货物费用之和。
折扣计算:企业客户(×0.8)或 个人客户(×0.9)应用折扣。
4. 输出生成:模板化与格式化
输出结构:
订单概览:客户信息、航班号、订单号、总重量、支付金额(含中文支付方式)。
货物明细表:制表符对齐的表格,列包括编号、名称、计费重量、费率、运费。
代码规模
第二次作业的代码规模如下图。

类图
第二次作业类图如下:

Main:程序入口,协调输入处理、订单生成、输出展示全流程
InputHandler:解析用户输入,构造业务对象
Cargo:实现ICargo接口,封装货物计费逻辑
Flight:管理航班载重限制
Order:整合订单全生命周期数据
Customer:存储客户详细信息
RateCalculator:根据货物类型和重量计算费率
ICargo:货物接口类
OutputHandler:格式化输出订单信息
复杂度分析
第二次作业的复杂度分析如下。

其中有几个方法复杂度稍高:
InputHandler.parseCargos()的iv(G)=3,
RateCalculator.calculateRate()的v(G)=4,
Bug分析
1.输入越界风险
问题现象:
未校验输入数据的完整性,当输入行数不足时会导致IndexOutOfBoundsException
2/货物解析时错误跳过不存在的Header行
问题现象:
在InputHandler.parseCargos()方法中,循环解析货物时强制跳过一行(currentIndex++),假设输入中存在类似"Cargo 1"的标题行。若实际输入不包含这些标题行,会导致货物数据错位。
潜在问题与注意事项
输入顺序敏感:必须严格按固定顺序输入,否则解析失败。
货物类型验证:未检查cargoType是否合法
精度丢失:运费计算使用double可能导致浮点误差
关于设计模式的思考
在实现代码的过程中,我从需求理解、模块划分到具体实现逐步深入,深刻体会到面向对象设计和业务逻辑解耦的重要性。以下是我的心路历程及核心思考。
一、需求分析与模块划分
代码的核心功能是处理货运订单,涉及客户信息、货物计费规则、航班容量校验及订单输出。通过阅读代码,我将其拆解为以下模块:
数据模型:Customer(客户)、Cargo(货物)、Flight(航班)、Order(订单)。
计费规则:RateCalculator根据货物类型动态计算费率。
输入输出:InputHandler解析输入数据,OutputHandler格式化输出。
业务逻辑:校验航班载重、计算折扣费用。
这一划分让我意识到,清晰的模块边界是降低复杂性的关键。例如,RateCalculator独立于货物类,使其计费规则可以灵活扩展。
二、面向对象设计的实践
接口与多态
ICargo接口定义了货物的核心行为(如getChargeableWeight),使得Cargo类能够通过实现接口保证功能的一致性。这种设计允许未来新增其他货物类型(如冷链货物)时,只需实现接口即可,无需修改现有逻辑。
策略模式的应用
RateCalculator将计费规则封装为独立类,根据货物类型(如“Normal”“Dangerous”)选择不同的费率计算策略。这体现了开闭原则——新增货物类型只需扩展策略,而非修改已有代码。不过,当前的switch语句稍显僵硬,未来可用工厂模式或枚举类优化。
组合优于继承
Order类通过组合Customer和Cargo对象管理订单,而非继承,避免了类层次过深的问题。同时,利用Java 8的Stream API(如cargos.stream().mapToDouble())简化了集合操作,提升了代码可读性。
三、总结与反思
通过实现此项目,我巩固了以下技能:
面向对象设计:通过接口、组合与策略模式解耦代码。
业务逻辑建模:将现实规则(如计费、航班载重)转化为代码结构。
代码可维护性:识别硬编码与脆弱设计,思考优化方案。
心得体会
1.面向接口编程的重要性:
上课老师向我们演示了接口的好处,而这次的题目刚好适合使用接口来实现。
代码均通过接口(如ICargo)定义行为,使得高层模块(如Order)不依赖具体实现,符合依赖倒置原则。这种设计让系统更灵活,易于应对需求变化。
2.单一职责原则(SRP)的落地:
单一职责原则说起来很简单,无非就是要强调一个类或模块应仅负责完成一个特定的职责或功能,但实际写起来才发现,单一职责原则不仅需要十分的认真对待,更是面向对象设计的基础。
例如,InputHandler和OutputHandler的分离,体现了“一个类只负责一个职责”。输入解析、输出渲染的逻辑独立变化,互不影响。
3.条件分支的优化方向:
每次看到代码中那一堆的if-else,我就感到十分头痛,在学习了多态后。遇到switch或if-else逻辑用于区分类型(如cargoType)时,应考虑用多态或策略模式替代。这不仅减少代码重复,还降低新增类型的成本。
4.组合与聚合的威力:
组合和聚集使用起来真的很方便!Order类组合Customer和Cargo对象,而非通过继承扩展功能。这种方式更灵活,且避免了继承层次的臃肿。

浙公网安备 33010602011771号