第二次blog作业 航空货运管理系统

一.前言

这一次的大作业与之前一次相比难度降低了一些,在我的努力下,我算是取得了不错的成绩。第一题着重要求了以下几点:单一职责原则、里氏代换原则、开
闭原则以及合成复用原则。
单一职责原则:一个类或模块应该只负责一项职责。
里氏代换原则:子类必须能够替换其父类,且程序的功能不会受到影响(即子类需完全实现父类的抽象方法,且行为符合父类预期)。
开闭原则:对扩展开放,对修改关闭。
合成复用原则:优先使用组合或聚合复用代码,而非继承。
而第二题就是在第一次基础上,进行继承与多态的运用。以更好的增强代码的可扩展性。总的来说,是一次非常有意思的挑战。

二.第一题

1.设计与分析

类图:

分析:这次作业让我对如何分类有了更加明确的认知。在设计类时,先明确业务核心为航空货运订单管理,需拆解为客户、货物、航班等独立实体,遵循单一职责原则。考虑到订单需整合多方信息,
采用合成复用原则组合各实体类。为确保数据逻辑内聚,让货物类专注运费计算,航班类管理载重,通过职责分离提升可维护性,最终形成当前类结构。通过不断的完善,做到了实现各个类都较好的实现了自己的职责,满足单一职责原则。
客户类(Customer):存储客户的基本信息(ID、姓名、电话、地址)仅作为数据载体,提供基本的 getter 和 toString 方法
与Order类关联,表示订单所属客户
货物类(Cargo):计算货物的体积重量、计费重量和运费。实现了货物运费计算的核心业务逻辑
与Order类关联,表示订单中的货物明细
航班类(Flight):管理航班信息和载重状态。被Order类复用,作为发件人和收件人的信息载体
与Customer类的区别:Customer是订单的客户,而Person是具体的联系人。
人员类(Person):存储发件人 / 收件人的基本信息。被Order类复用,作为发件人和收件人的信息载体
与Customer类的区别:Customer是订单的客户,而Person是具体的联系人
订单类(Order):整合订单的所有信息并生成订单详情。聚合了Customer、Flight、Person和Cargo对象
实现了订单业务的核心流程和输出。
主类(Main):程序入口,处理用户输入并创建订单。负责对象的创建和依赖注入
包含简单的业务规则校验(如航班载重检查)。

图片:

分析:代码规模:文件行数 278 ,语句数 172 。
语句占比:分支语句占比 5.8% ,方法调用语句数 56 ,注释行占比 4.0% 。
类与方法:类和接口数量 2 ,平均每个类的方法数 12.00 ,平均每个方法的语句数 6.79 。
复杂度:最复杂方法是 Main.main () ,位于 211 行 ,复杂度为 4 ;最深代码块在 225 行 ,最大代码块深度为 3 。
图表:Kiviat 图展示了平均复杂度、注释占比等指标;柱状图(Block Histogram)展示语句数量与代码块深度关系。
这次代码的设计,我自认为我有了较大的进步,能更好的根据单一职责原则来细分类。使得每个类的语句不会复杂,并且做到了很好的调用。但对于这样大作业,我应该准备更多时间来优化代码,
给代码加上更多的注释。以增强代码的可读性。但我觉得这一次Main.main ()。有点长,需要进一步进行改进优化。

2.踩坑心得:

在完成这个航空货运订单管理系统的过程中,我围绕业务场景进行类设计,逐渐体会到合理分层的重要性。最初设计类时,我将客户、货物、航班等实体独立拆分,确保每个类聚焦单一职责,比如Customer类仅存储客户基础信息,Cargo类专注于货物重量与运费计算逻辑,Flight类负责管理航班载重状态。这样的设计让代码结构更清晰,后续调试时也能快速定位问题。
编译过程中,我遇到了一些典型错误。例如,在Cargo类中计算体积重量时,误将除法运算符写为 “\” 而非 “/”,导致编译报错,这让我意识到细节检查的重要性。另外,在Order类的printOrder()方法中,曾因忘记导入DecimalFormat类而引发编译错误,这提醒我要确保依赖库的正确引入。还有一次,在Main类中读取用户输入时,未对空值进行处理,导致程序运行时抛出异常,后来通过增加输入校验逻辑解决了问题。
通过这次实践,我深刻认识到类设计需遵循 “高内聚、低耦合” 原则,而编译错误往往源于对细节的疏忽。每一次调试都是对代码逻辑的重新梳理,也让我更熟练地运用面向对象设计思想来构建系统。

3.改进建议:

类设计上,可将Order类的输出逻辑拆分到独立类,避免其同时承担计算与展示职责,强化单一职责;为货物运费计算创建抽象接口,采用策略模式封装费率规则,使新增货物类型时无需修改原有代码,满足开闭原则;通过组合FreightStrategy接口实现货物逻辑扩展,减少继承依赖,遵循合成复用原则。代码健壮性方面,在类构造方法中添加参数校验,如检查货物重量、航班载重是否有效,在输入层增加空值判断与格式校验,使用异常处理机制捕获输入转换等运行时异常,避免无效数据导致程序崩溃,同时规范代码结构,提升系统的可维护性与稳定性。

4.总结:

通过这道题,我对java如何从头到尾的设计一个程序有了更深的认知。通过的这次代码我尤其学会了cargo类,就是list在Java中的具体运用。通过本次实践,我不仅掌握了 Java 中类、集合、输入输出的核心用法,更学会了从业务需求出发设计程序结构。从单个类的属性方法定义,到多个类之间的协作,再到数据的流转与展示,每一个环节都需要结合实际场景反复推敲。未来需进一步强化异常处理、代码优化和模块化设计能力,让程序更健壮、易维护。

三.第二题

1.设计与分析

类图:

分析:这次作业让我对面向对象的分类设计有了更系统的理解。在设计类时,围绕航空货运订单管理这一核心业务,从业务场景中抽象出客户、货物、航班、支付方式等独立实体,并通过合理的继承、实现和组合关系,构建了层次清晰的类结构。是对继承相关知识运用的极大考验。

Customer 抽象类:定义客户的基础属性(ID、姓名、电话、地址)和公共方法(getName()、getPhone()、toString())。
声明抽象方法 getDiscountRate(),用于计算客户折扣率,由子类实现具体逻辑。子类:
IndividualCustomer(个人客户):实现个人客户 9 折优惠。
CorporateCustomer(集团客户):实现集团客户 8 折优惠。

Cargo 抽象类:定义货物的基础属性(ID、名称、尺寸、重量)和通用计算方法。 getVolumeWeight():计算体积重量(长 × 宽 × 高 ÷6000)。
getChargeableWeight():取实际重量与体积重量的较大值作为计费重量。
声明抽象方法 getRate(double weight),用于根据重量获取费率,由子类实现具体货物类型的费率规则。
calculateFreight():结合计费重量和费率计算运费。子类:
NormalCargo(普通货物):实现普通货物的阶梯费率(如 20kg 以下 35 元 /kg)。
DangerousCargo(危险货物):实现危险货物的高费率(如 20kg 以下 80 元 /kg)。
ExpediteCargo(加急货物):实现加急货物的中高费率(如 20kg 以下 60 元 /kg)。

Flight 类:职责:管理航班的基础信息(航班号、起降机场、日期、最大载重)和当前载重状态。
canCarry(double weight):校验航班是否可承载指定重量(当前载重 + 新增重量 ≤ 最大载重)。
addLoad(double weight):更新航班当前载重。

Person 类:职责:存储发件人 / 收件人的基础信息(姓名、电话、地址),提供数据访问方法(getName()、getPhone()、getAddress())。

PaymentMethod 接口:职责:定义支付方式的统一接口 getPaymentName(),用于获取支付方式名称。

Order 类 职责:整合订单的完整信息(订单编号、日期、客户、航班、发件人、收件人、货物列表、支付方式)。
核心业务方法:
getTotalWeight():计算订单总计费重量(所有货物计费重量之和)。
getTotalFreight():计算总运费(含客户折扣:各货物运费之和 × 折扣率)。
printOrder():格式化输出订单详情(客户信息、航班信息、发件人 / 收件人信息、货物明细、支付金额)。

Main 类 职责:程序入口,通过 Scanner 读取用户输入数据(客户类型、货物类型、航班信息、订单详情等)。
根据输入创建 Customer、Cargo、Flight、PaymentMethod 等对象,并注入到 Order 中。
执行业务校验(如航班载重检查),控制程序流程,最终创建并打印订单。

图片:

分析:文件共 424 行,含 147 条语句,分支语句占比 8.2% ,方法调用语句 20 条,带注释行占比 3.3% 。有 6 个类和接口,平均每个类有 6.67 个方法 ,每个方法平均含 3.45 条语句 。最复杂方法是 DangerousCargo.getRate () ,在 111 行,复杂度为 5 。最深块深度对应行号为 49 。有 6 个类和接口,平均每个类有 6.67 个方法 。类和方法数量较多,一定程度上体现了代码的模块化,但也可能存在职责划分不够清晰,导致类的功能不够单一的情况。最复杂的方法是DangerousCargo.getRate(),复杂度为 5 ,位于 111 行。这表明该方法可能存在较多的逻辑判断或嵌套,需要重点关注和优化。最深块深度为 49 行 ,反映了代码中嵌套结构的复杂程度,较深的块深度可能使代码逻辑难以理解和调试。

2.踩坑心得:

编写这段物流系统代码时,我踩过不少坑,也收获了宝贵经验。一是输入处理要谨慎,直接使用scanner.nextInt()会残留换行符,导致后续输入异常,必须用Integer.parseInt(scanner.nextLine())。二是抽象类与接口的设计很关键,合理定义抽象方法能让子类专注实现差异化逻辑,如Cargo类的费率计算。三是多态虽强大,但初始化对象时要注意类型匹配,否则会引发运行时错误。四是代码复用不能过度,像DecimalFormat应避免在循环中重复创建。五是业务校验不能少,如航班载重检查要在订单创建前完成。这些教训让我深刻意识到,写代码不能只追求功能实现,还要关注细节、优化结构,才能让程序更健壮、易维护。

3.总结:

本次代码编写围绕航空货运订单管理系统展开,通过对客户、货物、航班等业务实体的建模,深入理解了面向对象编程的核心思想。在代码实现中,通过抽象类与接口设计,系统性地运用了继承与多态机制,提升了代码的可扩展性与复用性。
在继承机制的实践中,定义抽象类Customer和Cargo作为业务基类,剥离出通用属性与行为。例如,Customer抽象类封装客户基础信息(ID、姓名、电话等),并声明抽象方法getDiscountRate(),由IndividualCustomer(个人客户,9 折)和CorporateCustomer(集团客户,8 折)子类实现差异化折扣逻辑。同理,Cargo抽象类定义体积重量、计费重量等通用计算方法,通过NormalCargo(普通货物)、DangerousCargo(危险货物)等子类实现不同货物类型的费率规则。这种层级结构使代码遵循 “开闭原则”,新增客户类型或货物类型时,只需扩展子类而无需修改基类代码。此外,通过接口PaymentMethod定义支付方式的统一行为getPaymentName(),由WechatPayment、AliPayPayment等实现类提供具体实现,进一步强化了多态的应用场景,体现了 “面向接口编程” 的设计原则。

posted @ 2025-05-25 11:33  BF2-SOAP  阅读(18)  评论(0)    收藏  举报