第二次Blog作业(航空货运管理系统)
一、前言
- 这是第二次java迭代作业,有两次迭代,相对于第一次迭代作业的三次迭代难度下降了许多,但是复杂程度有所提升:这一次的迭代作业主要考查的是类间关系的设计以及面向对象的设计原则。
- 这一次迭代作业完成得相对顺利,我也收获颇丰。
- 对于这次作业,如果能正确设计类与分析类与类之间的关系,做起来就能够得心应手。
二、设计与分析
第一次迭代
题目及要求:
某航空公司“航空货运管理系统”中的空运费的计算涉及多个因素,通常包
括货物重量/体积、运输距离、附加费用、货物类型、客户类型以及市场供需等。
本次作业主要考虑货物重量/体积,以下是具体的计算方式和关键要点:
一、计费重量的确定
空运以实际重量(GrossWeight)和体积重量(VolumeWeight)中的较
高者作为计费重量。
计算公式:
体积重量(kg)= 货物体积(长×宽×高,单位:厘米)÷6000
示例:
若货物实际重量为80kg,体积为120cm×80cm×60cm,则:
体积重量 =(120×80×60)÷6000=96kg
计费重量取96kg(因96kg>80kg)。
二、基础运费计算
费率(Rate):航空公司或货代根据航线、货物类型、市场行情等制定(如
CNY 30/kg)。本次作业费率采用分段计算方式:

公式:基础运费 = 计费重量 × 费率
三、题目说明
本次题目模拟某客户到该航空公司办理一次货运业务的过程:
航空公司提供如下信息:
航班信息(航班号,航班起飞机场所在城市,航班降落机场所在城市,航班
日期,航班最大载重量)
客户填写货运订单并进行支付,需要提供如下信息:
1、客户信息(姓名,电话号码等)
2、货物信息(货物名称,货物包装长、宽、高尺寸,货物重量等)
3、运送信息(发件人姓名、电话、地址,收件人姓名、电话、地址,所选航班号,订单日期)
4、支付方式(支付宝支付、微信支付)
注:一个货运订单可以运送多件货物,每件货物均需要根据重量及费率单独
计费。
程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信
息报表及货物明细报表。
四、题目要求
本次题目重点考核面向对象设计原则中的单一职责原则、里氏代换原则、开闭原则以及合成复用原则。
设计因素:单一职责原则(40%)、里氏代换原则(20%)、开闭原则(20%)、合成复用原则(20%)。
题目分析:
- (输入格式)题目要求首先用键盘按顺序输入:客户信息、货物信息、航班信息以及订单信息。
- (特殊要求)如果输入订单中货物重量超过航班剩余载重量,程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order. ,程序终止运行。
- (输出要求)如果航班载重量可以承接该订单,则要分别按每个货物的重量计算计费重量、费率和最终运费。
- (重点)遵循面向对象设计原则:单一职责原则、里氏代换原则、开闭原则、合成复用原则。
其中货运订单可以运送多件货物,故应该采用容器存储。
支付方式包含微信支付和支付宝支付,但是支付方式在此次的题目中并未出现选择。
解题思路:
- 首先我设计了几个实体类:
(1)Customer 类:用于表示客户信息,包含客户的 id、姓名、电话和地址等属性。通过提供属性的 getter 和 setter 方法,方便对客户信息进行访问和修改 ,体现了封装思想,将客户相关数据和操作封装在一起。
(2)Cargo 类:用来存储货物信息,有货物 id、名称、长宽高以及重量等属性,同样通过 getter 和 setter 方法实现对属性的操作,便于管理货物相关数据。
(3)Flight 类:存储航班信息,如航班 id、起始地址、结束地址、日期、最大载重和已用载重。最大载重是航班本身属性,已用载重会根据订单货物重量进行更新,用于判断航班是否超载。
- 其次是支付相关类,因为支付方法通常由第三方提供,而且支付途径多样易变,所以采用“接口-抽象类-普通类”的设计模式。
(1)Pay 接口:定义了支付的抽象行为pay(double charge) ,规范支付操作的形式。
(2)Payment 抽象类:实现 Pay 接口,提供一个空的构造方法,并将pay(double charge)方法定义为抽象方法,为具体支付方式子类提供统一抽象父类。
(3)WeChat 类和 Alipay 类:继承自 Payment 抽象类,分别实现pay(double charge)方法,实现微信和支付宝具体支付逻辑,打印支付金额,体现多态性,同一支付抽象行为有不同具体实现。
- 然后是计算相关类,由于计算方式容易变化,所以将计算方式独立出来。
(1)ChargeWeightCalculation 类:利用静态方法calculation(Cargo o) ,根据货物的实际重量和体积(长宽高计算得出),按照一定规则(取重量和体积 / 6000 的较大值)计算计费重量 ,实现计费重量计算逻辑的封装。
(2)FateCalculation 类:通过静态方法calculation(double weight)根据货物重量计算计费费率,不同重量区间对应不同费率,将费率计算逻辑封装在该类中。
- 接着是订单类,但是题目要求不同物品要分别管理和计费,而且要符合现实业务逻辑,模拟了真实订单结构。因此分别设计一个订单类和一个订单明细类,并设计为聚合的关系。
(1)OrderItem 类:表示订单中的单项货物信息,包含货物对象、计费重量、计费费率和费用等属性。通过调用 ChargeWeightCalculation 和 FateCalculation 类的方法来设置计费重量和费率,进而计算费用,将单个货物在订单中的相关计算和存储功能封装。
(2)Order 类:代表整个订单,包含订单基本信息(如 id、日期、收发件人信息等)、客户对象、航班对象、订单货物列表等。有方法用于设置和获取订单相关属性,还包括计算订单总重量、总费用,以及根据支付方式选择具体支付类等功能,将订单整体相关操作和数据管理封装。
- 最后是Main类,作为程序入口,通过Scanner从控制台读取用户输入信息,创建客户、货物、航班、订单等对象,进行相关属性设置和逻辑处理(如判断航班载重、计算订单费用、执行支付等),并输出订单相关信息。 它将各个类整合起来,实现整个业务流程的控制和交互。
代码分析:
1. 类图分析:

通过类图可以发现,这次作业的代码具有高内聚、复用性强的优点,也有高耦合度的缺点。它仍然可以进行进一步的优化。
2. SourceMonitor工具评估:
评估结果:

代码规模相关:
行数(Lines):500 行,体现文件总体长度。
语句数(Statements):275 条,是可执行及声明等语句数量。
分支语句百分比(Percent Branch Statements):2.5% ,分支语句(如 if、switch 等)在总语句中占比。
方法调用语句数(Method Call Statements):21 条,记录方法调用操作数量。
含注释行百分比(Percent Lines with Comments):0.0% ,说明代码中无注释行,不利于代码理解和维护。
结构与复杂度相关:
类和接口数量(Classes and Interfaces):11 个,反映代码结构复杂程度。
每类方法数(Methods per Class):平均 14.45 个 ,表明类的功能丰富度。
每个方法平均语句数(Average Statements per Method):0.86 条,方法较为简短。
最复杂方法行数(Line Number of Most Complex Method):158 行,对应方法是 FateCalculation.setUsedLoad() 。
最大复杂度(Maximum Complexity):6 ,体现最复杂方法的复杂度。
最深代码块行数(Line Number of Deepest Block):204 行。
最大代码块深度(Maximum Block Depth):3 ,反映代码嵌套层次。
平均代码块深度(Average Block Depth):1.47 。
平均复杂度(Average Complexity):1.08 ,整体方法复杂度较低。
第一次迭代总结:
这次作业内容偏简单,能够正确设计类和类间关系便可较轻松地完成。我这一次完成的比较顺利,为第二次迭代打下了较好的基础,但其中也有一些缺陷需要填补,代码才能变得完美,我才能变得更优秀。
第二次迭代
题目及要求:
某航空公司“航空货运管理系统”中的空运费的计算涉及多个因素,通常包
括货物重量/体积、运输距离、附加费用、货物类型、客户类型以及市场供需等。
本次作业主要考虑货物重量/体积,以下是具体的计算方式和关键要点:
一、计费重量的确定
空运以实际重量(GrossWeight)和体积重量(VolumeWeight)中的较
高者作为计费重量。
计算公式:
体积重量(kg)= 货物体积(长×宽×高,单位:厘米)÷6000
示例:
若货物实际重量为80kg,体积为120cm×80cm×60cm,则:
体积重量 =(120×80×60)÷6000=96kg
计费重量取96kg(因96kg>80kg)。
二、基础运费计算
1
费率(Rate):航空公司或货代根据航线、货物类型、市场行情等制定(如
CNY30/kg)。本次作业费率与货物类型有关,货物类型分为普通货物、危险货
物和加急货物三种,其费率分别为:

计算公式:基础运费 = 计费重量 × 费率 × 折扣率
其中,折扣率是指不同的用户类型针对每个订单的运费可以享受相应的折扣,
在本题中,用户分为个人用户和集团用户,其中个人用户可享受订单运费的9
折优惠,集团用户可享受订单运费的8折优惠。
三、题目说明
本次题目模拟某客户到该航空公司办理一次货运业务的过程:
航空公司提供如下信息:
航班信息(航班号,航班起飞机场,航班降落机场,航班日期,航班最大载
重量)
2
客户填写货运订单并进行支付,需要提供如下信息:
1、客户信息(姓名,电话号码等)
2、货物信息(货物名称,货物包装长、宽、高尺寸,货物重量等)
3、运送信息(发件人姓名、电话、地址,收件人姓名、电话、地址,所选
航班号,订单日期)
4、支付方式(支付宝支付、微信支付、现金支付)
注:一个货运订单可以运送多件货物,每件货物均需要根据重量及费率单独
计费。
程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信
息报表及货物明细报表。
四、题目要求
本次题目重点考核面向对象设计原则中的单一职责原则、里氏代换原则、开
闭原则以及合成复用原则、依赖倒转原则。
设计因素:单一职责原则(20%)、里氏代换原则(20%)、开闭原则(20%)、
合成复用原则(20%)、依赖倒转原则(20%)。
题目分析:
- (输入输出)与第一次迭代基本一致,但多加了客户类型、物品类型和支付方式
- (内容逻辑)客户和货物需加上“类型”的属性,费率、最终费用的计算需要更改。
解题思路:
大多数代码与第一次迭代的代码相似,这里就讲一讲不同点:
一、数据模型设计差异
- Customer类和Cargo类添加了type属性用于区分客户和货物的类型
- 支付方式扩展:新增了Cash(现金支付)方式
二、计费逻辑的复杂性差异
- 运费计算规则:运费计算同时考虑货物类型(Normal/Expedite/Dangerous)和重量,不同类型货物有独立的费率表。新增客户类型折扣:个人客户享 9 折,企业客户享 8 折。
- 计费逻辑实现:FateCalculation类的calculation方法增加了type参数,根据货物类型动态调整费率,体现了策略模式的应用。
三、订单处理流程差异
- 输入参数与业务流程:输入参数增加了客户类型(customerType)和货物类型(cargoType)。支付方式通过输入参数动态选择(Wechat/Cash/Alipay)
- 订单金额计算:总费用在货物费用之和的基础上,根据客户类型应用折扣(个人 9 折 / 企业 8 折)。
代码分析:
1. 类图分析:

相对于第一次迭代的代码,这一次的稍复杂了一些,但得益于第一次设计的基础打得比较好,并没有过大的改变。
2. SourceMonitor工具评估:

代码规模指标
行数(Lines):574 行,体现文件长度。
语句数(Statements):287 条,是可执行及声明等语句数量。
分支语句百分比(Percent Branch Statements):7.7% ,分支语句(如 if、switch 等)在总语句中占比。
方法调用语句数(Method Call Statements):30 条,记录方法调用操作数量。
含注释行百分比(Percent Lines with Comments):0.0% ,代码无注释,不利于理解维护。
代码结构指标
类和接口数量(Classes and Interfaces):13 个,反映代码结构复杂程度。
每类方法数(Methods per Class):平均 13.62 个 ,说明类功能丰富度。
每个方法平均语句数(Average Statements per Method):0.00 条,可能统计方式特殊或方法结构简单。
代码复杂度指标
最复杂方法行数(Line Number of Most Complex Method):{undefined} ,无。
最复杂方法名称(Name of Most Complex Method):{no methods} ,可能无复杂方法或统计异常。
最大复杂度(Maximum Complexity):0 ,方法复杂度极低。
最深代码块行数(Line Number of Deepest Block):173 行。
最大代码块深度(Maximum Block Depth):4 ,反映代码嵌套层次。
平均代码块深度(Average Block Depth):1.69 。
平均复杂度(Average Complexity):0.00 ,整体方法复杂度几乎为零。
其中:代码复杂度大大降低,这是非常好的一个点。代码嵌套层次也有所增加。
第二次迭代总结:
由于第一次迭代打下了较好的基础,这一次迭代完成的较为轻松,代码也有所优化:策略模式的深度体现、代码架构的可维护性提升、业务逻辑的灵活性与扩展性更佳、数据模型的业务适应性更强。从中,我获得了许多知识、经验和成就感。
三、心得体会
- 通过这两次的迭代作业(电梯和航天货运),我发现掌握面向对象技术并不是要求我们做出多么高深莫测的算法,相反,它更多的是将代码写得易懂、易改、逻辑清晰。它的内容正如它的名字“面对对象”,面对用户、方便程序员、拥抱多种变化。
- 这次作业的两次迭代中,我深刻的体会到:写代码前的设计有多么重要。这次作业的顺利进行,离不开第一次迭代前的仔细思考和设计。正是因为第一次迭代时类与类间关系的良好设计,第二次迭代时才能做到又快又好。
四、总结
这一次的航空货运管理系统作业让我对于类的设计有了进一步的认识与理解。从电梯作业到本次作业的学习过程,让我从会写逐步晋级为会设计。通过面向对象技术的不断深入学习,我了解到每一个类无论大小都是代码的重要组成部分,如果不在编写前仔细思考与设计,容易造成类间关系盘根错节,此时想要修改代码就容易“牵一发而动全身”。因此在今后的代码编写前,一定要认真思考:该如何创建类?类与类之间有着怎样的关系?这样做出来的“产品”才能是“好产品”。

浙公网安备 33010602011771号