导航

OO-PTA题目集8,9航空货运总结

Posted on 2025-05-22 15:39  又出bug了  阅读(16)  评论(0)    收藏  举报

一、前言

第二次blog作业,对PTA8,9题目集中的航空货运管理系统题目进行分析和总结。这两次题目的质量不在算法上,而在设计上,要用到类的封装、继承、多态,抽象类和接口,重点要符合单一职责原则、里氏代换原则、开闭原则、合成复用原则、依赖倒转原则。
题目集8:
一共三道题,前两题都是对之前题目的类设计进行重构,以实现继承与多态的技术性需求,使得程序可以对功能进行扩展。题量中等,难度中等。
题目集9:
一共三道题,也是考核的是继承与多态的运用,通过继承和多态实现程序的可扩展性。第二题要设计容器类保存对象,并能实现增、删、遍历操作。题量中等,难度中等。

二、设计与分析

第一次航空货运

题目说明及要求:

一、计费重量的确定

空运以实际重量(GrossWeight)和体积重量(VolumeWeight)中的较高者作为计费重量。
计算公式:
体积重量(kg)= 货物体积(长×宽×高,单位:厘米)÷6000
示例:
若货物实际重量为80kg,体积为120cm×80cm×60cm,则:
体积重量 =(120×80×60)÷6000=96kg
计费重量取96kg(因96kg>80kg)。

二、基础运费计算

费率(Rate):航空公司或货代根据航线、货物类型、市场行情等制定(如CNY 30/kg)。本次作业费率采用分段计算方式:

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

三、题目说明

本次题目模拟某客户到该航空公司办理一次货运业务的过程:
航空公司提供如下信息:
航班信息(航班号,航班起飞机场所在城市,航班降落机场所在城市,航班日期,航班最大载重量)
客户填写货运订单并进行支付,需要提供如下信息:
客户信息(姓名,电话号码等)
货物信息(货物名称,货物包装长、宽、高尺寸,货物重量等)
运送信息(发件人姓名、电话、地址,收件人姓名、电话、地址,所选航班号,订单日期)
支付方式(支付宝支付、微信支付)
注:一个货运订单可以运送多件货物,每件货物均需要根据重量及费率单独计费。
程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信息报表及货物明细报表。

四、题目要求

本次题目重点考核面向对象设计原则中的单一职责原则、里氏代换原则、开闭原则以及合成复用原则,除需要在PTA平台提交源码外,还需要在超星平台提交本次作业最终得分源码(首次提交最高分源码)的类图,评判标准为:
基础得分:PTA实际得分
设计因素:单一职责原则(40%)、里氏代换原则(20%)、开闭原则(20%)、合成复用原则(20%)

输入输出

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

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

输出格式:
· 如果订单中货物重量超过航班剩余载重量,程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order.,程序终止运行。
· 如果航班载重量可以承接该订单,输出如下:

客户:姓名(电话)订单信息如下:
-----------------------------------------
航班号:
订单号:
订单日期:
发件人姓名:
发件人电话:
发件人地址:
收件人姓名:
收件人电话:
收件人地址:
订单总重量(kg):
微信支付金额:

货物明细如下:
-----------------------------------------
明细编号    货物名称    计费重量    计费费率    应交运费
1    ...
2    ...

注:输出中实型数均保留1位小数。

类图

分析报表

设计了CalculateRate接口和Display接口,CalculateRate接口用于计算费率,由Rate类来实现。Goods类有getChargeWeight()(获取计费重量)、getRate()(获取费率)、getPrice()(获取运费)三个方法,其中getRate()方法依赖于Rate类。OrderItem类(订单项)有Goods类型的属性,Order类(订单)再聚集订单项。Person类为抽象类,Client类(客户)、Sender类(寄件人)、Receiver类(收件人)都继承自Person类,Order类有Client类型的属性。Payment类为抽象类,WeChatPay类(微信支付)、AliPay类(支付宝支付)都继承自Payment类,Order类的pay()方法要依赖Payment类。Controller类用于把要输出的内容综合在一起,如Cilent、Order、Flight(航班)、Sender、Receiver,再通过实现Display接口来做到展示订单信息和货物明细。
这次题目难度不大,上课认真听了就能写出来,从分析结果来看,注释较少,复杂度低,我再回头看时,程序有许多冗余代码,都是可以从父类中继承来的,就比如Person类,把属性的修饰符都换成protected修饰符,子类就不用覆写这么多一模一样的方法了,在构造子类对象时用super关键字调用父类的构造方法即可。

第二次航空货运

新增需求

客户类型分为个人(Individual)和集团(Corporate)
货物类型分为普通货物(Normal)、危险货物(Dangerous)和加急货物(Expedite)三种,其费率分别为:

支付方式有Wechat、ALiPay、Cash
计算公式:基础运费 = 计费重量 × 费率 × 折扣率
其中,折扣率是指不同的用户类型针对每个订单的运费可以享受相应的折扣,在本题中,用户分为个人用户和集团用户,其中个人用户可享受订单运费的9折优惠,集团用户可享受订单运费的8折优惠。
输入格式:

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

类图

分析报表

依然是两个接口CalculateRate接口和Display接口,不一样的是删除了Rate类,Goods类做成抽象类并且实现CalculateRate接口,子类有NormalGoods类、ExpediteGoods类、DangerousGoods类,每个子类都有自己的计算费率的方法,Goods类的getChargeWeight()(获取计费重量)、getRate()(获取费率)、getPrice()(获取运费)三个方法都拿掉给了OrderItem类。
简单工厂模式,通过switch语句来获取货物类型并创建相应货物,符合开闭原则,用户的折扣率也是通过switch语句来获得。这次把抽象类中的属性都用protected修饰符修饰,冗余代码大大减少,提高了代码可读性和可维护性。

三、采坑心得

题目集8的第二题雨刮器功能扩展踩了两个坑:第一个是要求用到抽象类和接口,但是这个要求很隐蔽,导致我没有看到也就没有用上抽象类和接口。第二个是不清楚父类和子类相同方法之间的关系,因为在构造子类时会先默认super()一个父类对象,然后就以为子类的方法中也要有super来先调用父类中的方法,这就导致子类的方法在和父类的方法在“打架”一样,后面了解了super的用法才知道正确的做法。
第一次航空货运里抽象类的属性都是private修饰的,导致冗余代码占程序的一半左右。因为当时也是刚接触抽象类,其中的内容也是一知半解,在后来才知道如果子类方法和父类方法逻辑一模一样时可以用super来直接调用父类的方法,子类就不需要多写。
还有一个我不知道是否算踩坑,航空货运中的Controller类有Cilent、Sender、Receiver三个具体类的属性,根据依赖倒转原则,应该依赖这三个具体类的抽象类也就是Person类,而两次航空货运都没有依赖抽象,因为内心的想法是Cilent类有Person类没有的方法。但现在看来,可以用一个List来存放三个人(客户、寄件人、收件人),然后要用到某一类型的人的方法时,用强制转换符()来向下转型为对应类型再去调用方法。

不论以后是在做题的时候,还是更加以后上班做项目的时候,都要把要求(需求)看清楚、想明白才开始着手。

四、改进建议

1.Controller类的变化(也在踩坑心得中提到过),可以用一个List来存放Cilent、Sender、Receiver属性,这样就依赖抽象,而不是依赖具体。
2.客户的类型、货物的类型定义成枚举类,这样可以减少字符串比较的错误,并且使代码更具可读性和可维护性。
3.货物类型的校验,在switch语句之外,应该有一个默认的case来处理未知的货物类型。这样可以避免创建null对象。

五、总结

经过本阶段两次题目集,我学到了抽象类和接口的正确使用方法,简单工厂模式的使用。在编码时要注重原则,评判一个程序是否为好的程序依靠的就是原则,让原则内化于心、外化于行。