题目集8~9总结

题目集8~9总结

一、前言

1、知识点

(1)继承:子类(派生类)继承父类(基类)的属性和方法,实现代码复用;

(2)Java只支持单继承(一个子类只能有一个直接父类);

(3)子类可覆盖父类方法(@Override注解);

(4)访问父类成员:super.method();

(5)子类构造器默认调用super(),需满足先构造父类再构造子类;

(6)里氏替换原则(LSP):子类必须能完全替代父类,不改变原有逻辑;

(7)多态:同一操作作用于不同对象时产生不同行为;

(8)编译时多态 方法重载(Overload)void print(int i) 和 void print(String s);

(9)运行时多态 方法重写(Override)父类引用调用子类实现。

(10)单一职责原则、里氏代换原则、开 闭原则以及合成复用原则的应用。

2、题量

两次次题目集都是三道题,题量不多。

(1)第一次“航空货运管理系统”题目:

航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明如下:
某航空公司“航空货运管理系统”中的空运费的计算涉及多个因素,通常包 括货物重量/体积、运输距离、附加费用、货物类型、客户类型以及市场供需等。 本次作业主要考虑货物重量/体积,以下是具体的计算方式和关键要点:

 

1)计费重量的确定

空运以实际重量(Gross Weight)和体积重量(Volume Weight)中的较 高者作为计费重量。

计算公式: 体积重量(kg) = 货物体积(长×宽×高,单位:厘米)÷ 6000

示例: 若货物实际重量为 80kg,体积为 120cm×80cm×60cm,则: 体积重量 = (120×80×60) ÷ 6000 = 96kg 计费重量取 96kg(因 96kg > 80kg)。

2)基础运费计算

费率(Rate):

 

航空公司或货代根据航线、货物类型、市场行情等制定(如 CNY 30/kg)。

本次作业费率采用分段计算方式:

公式:基础运费 = 计费重量 × 费率

3)题目说明

本次题目模拟某客户到该航空公司办理一次货运业务的过程: 航空公司提供如下信息: 航班信息(航班号,航班起飞机场所在城市,航班降落机场所在城市,航班 日期,航班最大载重量)

客户填写货运订单并进行支付,需要提供如下信息:

 客户信息(姓名,电话号码等)

 货物信息(货物名称,货物包装长、宽、高尺寸,货物重量等)

 运送信息(发件人姓名、电话、地址,收件人姓名、电话、地址,所选 航班号,订单日期)

 支付方式(支付宝支付、微信支付)

注:一个货运订单可以运送多件货物,每件货物均需要根据重量及费率单独 计费。 程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信 息报表及货物明细报表。

4)题目要求

本次题目重点考核面向对象设计原则中的单一职责原则、里氏代换原则、开 闭原则以及合成复用原则。

 

输入格式:
按如下顺序分别输入客户信息、货物信息、航班信息以及订单信息。

客户编号
客户姓名
客户电话
客户地址
运送货物数量
[货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为YYYY-MM-DD)
航班最大载重量
订单编号
订单日期(格式为YYYY-MM-DD)
发件人地址
发件人姓名
发件人电话
收件人地址
收件人姓名
收件人电话

(2)第一次“航空货运管理系统”题目:

这次题目与第一次题目内容大体相同,有部分修改

费率(Rate):航空公司或货代根据航线、货物类型、市场行情等制定(如CNY 30/kg)。本次作业费率与货物类型有关,货物类型分为普通货物、危险货物和加急货物三种,其费率分别为:

 计算公式:基础运费 = 计费重量 × 费率 × 折扣率

其中,折扣率是指不同的用户类型针对每个订单的运费可以享受相应的折扣,在本题中,用户分为个人用户和集团用户,其中个人用户可享受订单运费的 9折优惠,集团用户可享受订单运费的 8 折优惠。

 

输入格式:
按如下顺序分别输入客户信息、货物信息、航班信息以及订单信息。

 

客户类型[可输入项:Individual/Corporate]
客户编号
客户姓名
客户电话
客户地址
货物类型[可输入项:Normal/Expedite/Dangerous]
运送货物数量
[货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为YYYY-MM-DD)
航班最大载重量
订单编号
订单日期(格式为YYYY-MM-DD)
发件人地址
发件人姓名
发件人电话
收件人地址
收件人姓名
收件人电话
支付方式[可输入项:Wechat/ALiPay/Cash]

 

 

 

3、难度

两次题目集难度中等。

(1)第一次题目集前两题大概花了3小时,第三题花的时间较久,大概有5小时,这题主要考察面向对象设计原则,我没办法很好地设计每个类之间的关系。

(2)第二次题目集前两题也是差不多花了3小时,第三题相对于第一次花的时间要少了点,有了上一次题目集的基础,花了1个半小时左右。

二、设计与分析

“航空货运管理系统”源代码分析、解释与心得

(1)第一次“航空货运管理系统”源代码分析:

1.类图

2.SourceMontor的生成报表

 

 

解释与心得:

(1)据图可知Main.java 的 Avg Sims/Method(36.00)极高,说明 main 方法可能包含过多逻辑,也许可以拆分为多个小方法。其他代码度量数据在范围内。

(2)可以将不同模块的输入操作封装成方法,拆分出客户信息输入方法、货物信息输入方法、航班信息输入方法、收发货人信息输入方法。

 

解释与心得:

(1)该Agent类符合中介模式集中管理订单、客户、航班等对象的交互。但是Agent.java(13方法)的Methods/Class(方法数/类)较多,可能违反了单一职责原则。

(2)orderReport() 方法封装了所有报告生成逻辑,违反了单一职责原则,Agent应只负责协调,不直接处理业务逻辑,应该将报告生成委托给专门类。

 

 

解释与心得:

(1)基本封装了订单核心属性,如ID、航班、货物列表、日期,提供了必要的业务方,计算总重量、校验航班载重,使用泛型集合 ArrayList<CargoItem> 确保类型安全。

(2)validFlightWeight() 方法实际属于航班载重校验逻辑,更适合放在 Flight 类。

                

 

解释与心得:

(1)支付方式应用了继承与多态。

(2)符合开闭原则,新增支付方式只需扩展新类,无需修改现有代码;拥有可替换性,支付方式依赖抽象,而非具体实现;便于统一管理,所有支付方式遵循相同接口,便于批量操作(如退款检查)

 

解释与心得:

(1)Cargoterm类(18方法)Methods/Class(方法数/类)较多,可能违反了单一职责原则。Cargoterm类 的复杂分支较多,长期维护时可能难以理解业务逻辑。Cargoterm类的值为 6(其他文件均 ≤3),Max Complexity(最大圈复杂度)较高,可能需要重构。

(2)违反单一职责原则,同时承担数据存储、费率计算、运费计算三种职责硬编码业务规则,费率计算直接写在实体类中,难以修改。

(3)起初我是尝试把费率计算放在了专门的类中,但是最后运行时显示逻辑错误,没有找到解决方案,就放在了订单明细中。

 

         

 

 

(2)第二次“航空货运管理系统”源代码分析:

1.类图

 

 

2.SourceMontor的生成报表

 

解释与心得:

(1)写过第一次的“航空货运管理系统”题目后,我感觉将输出订单信息放在中介类中不合适,便拿掉了中介类,并且使订单信息直接在主类的主方法中输出,但是反而使Avg Complexity(平均复杂度)增加了,需要重构该类,第一次“航空货运管理系统”题目存在的问题仍然存在。

(2)同时跟第一次“航空货运管理系统”题目我所写的代码相比代码质量有所下降,对单一职责原则的应用还不够透彻。

         

         

解释与心得:

(1)Order类为Customer1与Customer2两个类的父类,Custermable为Order类连接的接口。

(2)Order类中的Methods/Class(方法数/类)较多,有类似第一次“航空货运管理系统”题目中所写代码的问题,但是也有所改善,相比于上次,这次没有判断是否超重的方法。

          

     

解释与心得:Cargoterm类(18方法)Methods/Class(方法数/类)较多,依然跟第一次“航空货运管理系统”题目有相同问题,还是没有找到将计算费率放在专门的类中的解决方案,(其实我觉得放在这个类里面应该也没问题?)。

          

    

三、踩坑心得

第一次“航空货运管理系统”踩坑心得:

(1)中介类应只负责协调,不直接处理业务逻辑,题目中虽然Agent类符合中介模式集中管理订单、客户、航班等对象的交互。但是Agent.java(13方法)的Methods/Class(方法数/类)较多,其中违反了单一职责原则。orderReport() 方法封装了所有报告生成逻辑,违反了单一职责原则,Agent应只负责协调,不直接处理业务逻辑,应该将报告生成委托给专门类。

(2)Cargoterm类(18方法)Methods/Class(方法数/类)较多,Cargoterm类 的复杂分支较多,长期维护时可能难以理解业务逻辑。Cargoterm类的值为 6(其他文件均 ≤3),Max Complexity(最大圈复杂度)较高,可能需要重构。Cargoterm类违反单一职责原则,同时承担数据存储、费率计算、运费计算三种职责硬编码业务规则,费率计算直接写在实体类中,难以修改。

 

第二次“航空货运管理系统”踩坑心得:

(1)代码拿掉了中介类,并且使订单信息直接在主类的主方法中输出。可以将订单信息输出放在专门的类中。

(2)Order类中的Methods/Class(方法数/类)依旧较多,有类似第一次“航空货运管理系统”题目中所写代码的问题,出现职责泛滥的现象。

四、改进建议

(1) 减少过长方法(拆分逻辑),如第二次题目我的代码中的Main类一个方法有120行,可以将不同模块的输入操作封装成方法,拆分出客户信息输入方法、货物信息输入方法、航班信息输入方法、收发货人信息输入方法。
(2) 降低各类之间的耦合度,在第一次题目中Order类与Flight类耦合度较高。
(3)减少类的方法数量,遵循单一职责原则。第一次与第二次题目的CargoItem都未遵循单一职责原则,以及第一次题目的Agent和Order类也未遵循单一职责原则,这几个类都需要重构。
(4)重构高复杂度方法(如 >10)。第二次题目主类需要重构,
(5)减少代码块的嵌套层数(如深度 ≤3)。
(6)方法的平均复杂度,控制整体复杂度(如 ≤5)。如使第二次题目中我使订单信息直接在主类的主方法中输出,但是反而使Avg Complexity(平均复杂度)增加了,代码质量下降,需要重构该类。

(7)Cargoterm类 的复杂分支较多,长期维护时可能难以理解业务逻辑,建议减少分支数。

 

五、总结

通过这两次题目集我学到了:

(1)中介类的核心目标是减少对象间的直接耦合,通过集中管理交互逻辑来简化系统架构。上帝类会直接操作所有对象,导致高耦合(我的代码就出现这种情况)。中介类是通过单一协调点降低依赖,符合迪米特法则。

(2)继承与多态:

1)继承

‌继承‌允许一个类(子类)自动获得另一个类(父类)的属性和方法。通过继承,子类可以重用父类的代码,避免重复编写相似的代码,同时可以添加自己的特有功能。继承的作用包括代码重用‌:避免重复编写相同的代码,提高开发效率。还能建立类层次结构‌:通过“is-a”关系组织类,如“狗是动物”,形成清晰的类结构。

2)多态
‌多态‌允许对象在运行时根据其实际类型来选择执行的方法。同一个方法名可以有不同的实现,具体调用哪个实现由对象的实际类型决定。多态的作用包括增强代码的灵活性和扩展性‌,通过动态绑定(运行时多态),在运行时决定调用哪个方法。

(3)单一职责原则、里氏代换原则、开 闭原则以及合成复用原则的应用

1)对单一职责原则的应用更加熟练。

2)里氏代换原则‌是要求所有引用基类的地方必须能够透明地使用其子类的对象。这两次题目中我的代码都是符合该原则的。

3)开闭原则‌要求软件实体对扩展开放,对修改关闭。第一次题目的支付方式,第二次题目的客户类型、货物类型、支付方式都符合开闭原则。

posted @ 2025-05-25 17:39  泽夏  阅读(20)  评论(0)    收藏  举报