航空货运管理系统总结性blog

一,前言

  1. 前两次作业的知识点主要涉及类的继承与多态还有接口等等,重点考核面向对象设计原则中的单一职责原则、里氏代换原则、开闭原则以及合成复用原则,锻炼了学生对各个原则的理解能力。
  2. 难度方面主要集中在设计,算法方面并没有多大的难度,并且考察个人对于类的设计能力。
  3. 题目量较少,完全可以在规定时间内自己完成

二,设计与分析

第一次题目要求如下

点击查看题目要求
航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计

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

客户编号
客户姓名
客户电话
客户地址
运送货物数量
[货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为YYYY-MM-DD)
航班最大载重量
订单编号
订单日期(格式为YYYY-MM-DD)
发件人地址
发件人姓名
发件人电话
收件人地址
收件人姓名
收件人电话
输出格式:
如果订单中货物重量超过航班剩余载重量,程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order. ,程序终止运行。
如果航班载重量可以承接该订单,输出如下:
客户:姓名(电话)订单信息如下:
-----------------------------------------
航班号:
订单号:
订单日期:
发件人姓名:
发件人电话:
发件人地址:
收件人姓名:
收件人电话:
收件人地址:
订单总重量(kg):
微信支付金额:

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

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

费率(Rate):航空公司或货代根据航线、货物类型、市场行情等制定(如
CNY 30/kg)。本次作业费率采用分段计算方式:
重量小于20,费率为35。
重量大于等于20小于50,费率为30。
重量大于等于50小于100,费率为25。
重量大于等于100,费率为15。
公式:基础运费 = 计费重量 × 费率

根据题目要求设计的类图如下

以上类图显示我设计了多个类,Main类,Order类,Person类,Client类,Computeall类,Flight类,Goods 类
以下是对相应类做的解释

  • Main 类:程序入口,有 main 方法,是程序启动后最先执行的部分,负责程序初始化与流程控制。

  • Order 类:订单类,聚合了 Client、Goods、Flight 等信息,还有订单编号、日期等属性。提供一系列 setter 和 getter 方法来操作属性,show 方法可以展示订单详情。

  • Person 类:抽象类,定义了人员的通用属性(姓名、电话、地址)和相关访问、修改方法。Acceptperson 和 Sendperson 继承自 Person,分别表示收件人和寄件人,在继承基础上可添加各自特有属性和方法。

  • Client 类:表示客户,有编号属性,通过构造函数和 setter、getter 方法操作属性。

  • Computeall 类:可用于计算相关业务逻辑,如费用等。有计算金额和总重量的方法,接收可计费重量和商品列表等参数。

  • Flight 类:航班类,包含航班编号、出发地、目的地、日期、重量等属性,有对应属性的访问和修改方法。

  • Goods 类:商品类,有编号、名称、长宽高等属性,提供属性访问和修改方法,Goods 构造函数可初始化商品信息。

关系分析

  • 继承关系:Acceptperson 和 Sendperson 继承自 Person,体现了面向对象的继承特性,复用 Person 的属性和方法并可扩展。
  • 关联关系:Order 类与 Client、Goods、Flight 等类关联,表明订单与客户、商品、航班紧密相关。

代码分析图如下

根据分析图可知

  1. 整体信息
    代码基本信息:含 413 行代码,有 162 条语句 ,分支语句占比 0.6% ,方法调用语句有 15 条 ,带注释的行占比 5.8% 。
  2. 结构相关
    类和接口数量:定义了 3 个类或接口 ,平均每个类有 17.33 个方法。
    方法平均情况:平均每个方法有 2.81 条语句 ,最复杂方法的行数为 9 。
  3. 复杂度分析
    最复杂的方法是 Acceptperson.Acceptperson() ,复杂度为 1 ,最大嵌套深度(块深度)为 2 。整体平均复杂度为 1.00 ,平均块深度为 0.64 ,最深块的行号是 10 。
    复杂方法列表:列出了多个类中较复杂的方法,如 Person 类的 getAddress() 、getName() 等方法,以及 Sendperson.Sendperson() 方法,这些方法复杂度大多为 1 ,语句数 1 - 3 条 ,最大深度多为 2 ,部分方法无调用(调用数为 0 )。
  4. 块深度与语句分布
    块深度为 0 的语句有 70 条,深度为 1 的有 80 条,深度为 2 的有 12 条 ,深度 3 及以上无语句。
  5. Kiviat 图展示了代码在注释比例、平均复杂度、最大复杂度、最大深度、平均深度、每个类的方法数、每个方法的平均语句数等维度的情况;柱状图直观呈现了语句数与块深度的关系 ,可以看出大部分语句集中在块深度 0 和 1 。

总体来看,代码结构较为规整,方法复杂度普遍较低,代码的嵌套层次不深,代码注释占比较少。
根据分析可知代码还算完善,但是注释较少,需要提高注释

第二次题目要求如下

在题目集8的基础上对费率计算做了更改,新增了用户类型的输入,货物类型的输入,以及支付方法的输入

  1. 费率(Rate):航空公司或货代根据航线、货物类型、市场行情等制定(如 CNY30/kg)。本次作业费率与货物类型有关,货物类型分为普通货物、危险货 物和加急货物三种,其费率分别为:
  2. 用户类型:当输入的用户类型为Individual时支付时可以打九折,当输入的用户类型为Corporate时支付时可以打八折
  3. 支付方法:根据输入支付方法的不同在输出时,所表现的输出结果中的支付方法也会有所不同

根据题目要求,设计出的类图如下

根据以上类图说明我设计了多个类,有Person 类,Client 类,Sendperson 类和 Acceptperson 类,Goods 类,Flight 类,Order 类,Computeall 类
以下是对相应类做的解释

  • Person 类
    是一个基础类,封装了 name、phonenumber、address 等个人基本信息及对应的访问器和修改器方法。
    作为父类,被 Client、Sendperson、Acceptperson 继承
  • Client 类
    继承自 Person 类,在拥有 Person 类属性和方法基础上,增加了 number 属性,用于标识客户编号 ,用于客户管理、订单关联等场景。
  • Sendperson 类和 Acceptperson 类
    均继承自 Person 类,分别代表发件人和收件人角色。
  • Goods 类
    用于描述货物信息,包含货物编号(number)、名称(name)、尺寸(width、length、high )、重量(weight)等属性,还涉及体积重量(volumeweight)、计费重量(chargeableweight)计算相关属性。
    并提供对应方法访问和修改这些信息,方便对货物各项信息进行操作。
  • Flight 类
    封装了航班相关信息,如航班号(number)、起飞机场(departure)、降落机场(landing)、日期(day)、最大载重量(weight),并提供对应方法访问和修改这些信息。
  • Order 类
    是系统核心业务类之一,通过组合关系聚合了 Client、List、Flight、Sendperson、Acceptperson 等对象,还包含订单编号(number)、日期(day)等自身属性 ,以及用于展示订单信息的 show() 方法。
  • Computeall 类
    专注于计算相关功能,包含计算货物运费(getmoney )、总运费(getallmoney )、总重量(getallheight )、费率(getRates )等方法,为订单运费计算等业务逻辑提供支持。
    关系分析
    继承关系:Client、Sendperson、Acceptperson 继承自 Person ,体现了类的层次结构和代码复用,子类可继承父类属性和方法并进行扩展。
    组合关系:
    Order 类组合了 Client、Goods、Flight、Sendperson、Acceptperson 等类的对象,表明订单由这些实体共同构成。
    Goods 类作为 Order 类的一部分,体现了整体 - 部分关系,订单包含多个货物,货物是订单的组成元素 。

代码分析图如下

根据分析图可知

  1. 整体信息
    代码有 472 行代码,包含 181 条语句 ,分支语句占比 2.2% ,方法调用语句有 22 条 ,带注释的行占比 5.7%。
    类与方法数量:定义了 3 个类或接口 ,平均每个类有 18.67 个方法,平均每个方法有 2.93 条语句 。方法数量较多,但平均语句数不算高,说明方法功能可能相对单一,但众多方法也可能导致类的职责不够清晰,可进一步审视类的设计是否符合单一职责原则。
  2. 复杂度分析
    方法复杂度:最复杂的方法是 Acceptperson.Acceptperson() ,复杂度为 1 ,最大嵌套深度(块深度)为 2 。整体平均复杂度为 1.00 ,平均块深度为 0.66 ,最深块的行号是 10 。这表明代码整体复杂度较低,方法逻辑相对简单。
    复杂方法列表:列出的较复杂方法中,如 Person 类的多个属性访问和设置方法,以及 Acceptperson.Acceptperson()、Sendperson.Sendperson() 等构造方法,复杂度大多为 1 ,语句数较少,深度多为 2 ,部分方法无调用(调用数为 0 )。
  3. 块深度与语句分布
    块深度分布:块深度为 0 的语句有 77 条,深度为 1 的有 89 条,深度为 2 的有 15 条 ,深度 3 及以上无语句。说明大部分语句处于较浅的嵌套层次,代码逻辑的嵌套结构不复杂。
    可视化图表:Kiviat 图展示了代码在注释比例、平均复杂度、最大复杂度、最大深度、平均深度、每个类的方法数、每个方法的平均语句数等维度的情况;柱状图直观呈现了语句数与块深度的关系 ,可以看出大部分语句集中在块深度 0 和 1

总体而言,第二次题目的代码结构相对简单,复杂度低,易于理解和维护,但存在注释不足、类中方法数量较多可能导致职责不够清晰等问题。

三,踩坑心得

  1. 踩坑点一
第一次设计时我设计的Computeall类如下
class Computeall{
    public  double getmoney(double Chargeableweight){
        double x=Chargeableweight;
        //费率35
        if(x>0&&x<20){
            return x*35;
        }
        //费率30
        if(x>=20&&x<50){
            return x*30;
        }//费率25
        if(x>=50&&x<100){
            return x*25;
        }//费率15
        if(x>=100) {
            return x * 15;
        }
        else{
            return 0;
        }
    }
    public  double getallmoney(List<Goods> goods){
        int x=goods.size();
        double temp=0;
        for(int i=0;i<x;i++){
            temp+=this.getmoney(goods.get(i).getChargeableweight());
        }
        return temp;
    }
    //获取总重量
    public  double getallheight(List<Goods> goods){
        int x=goods.size();
        double temp=0;
        for(int i=0;i<x;i++){
            temp+=goods.get(i).getChargeableweight();
        }
        return temp;
    }
    public double getRates(double chargeableweight){
        double x=chargeableweight;
        //费率35
        if(x>0&&x<20){
            return 35;
        }
        //费率30
        if(x>=20&&x<50){
            return 30;
        }//费率25
        if(x>=50&&x<100){
            return 25;
        }//费率15
        if(x>=100) {
            return 15;
        }
        else{
            return 0;
        }
    }
}

在我设计的方法中我认为我设计的三个方法getmoney,getallmoney,getRates,getallheight设计的并不合理,比如我在getmoney中直接根据货物重量范围设计多个if语句来计算所需的费用,但是这样造成了代码的多余,而且并未合理发挥getrates的作用

第二次设计时我设计的Computeall类如下
class Computeall{
    public  double getmoney(double Chargeableweight,String type1){
        double x1=Chargeableweight;
        double x2=getRates(x1,type1);
        return x1*x2;
    }
    public  double getallmoney(List<Goods> goods, Client client){
        int x=goods.size();
        double temp=0;
        for(int i=0;i<x;i++){
            temp+=this.getmoney(goods.get(i).getChargeableweight(),goods.get(i).getType());
        }
        if(client.getType().equals("Individual")){
            return temp*0.9;
        }
        if(client.getType().equals("Corporate")){
            return temp*0.8;
        }
        return 0;
    }
    //获取总重量
    public  double getallheight(List<Goods> goods){
        int x=goods.size();
        double temp=0;
        for(int i=0;i<x;i++){
            temp+=goods.get(i).getChargeableweight();
        }
        return temp;
    }
    public double getRates(double chargeableweight,String type){
        double x=chargeableweight;
        //正常货物
        if(type.equals("Normal")) {
            if (x > 0 && x < 20) {
                return 35;
            }
            if (x >= 20 && x < 50) {
                return 30;
            }
            if (x >= 50 && x < 100) {
                return 25;
            }
            if (x >= 100) {
                return 15;
            } else {
                return 0;
            }
        }
        //加急货物
        if(type.equals("Expedite")) {
            if (x > 0 && x < 20) {
                return 60;
            }
            if (x >= 20 && x < 50) {
                return 50;
            }
            if (x >= 50 && x < 100) {
                return 40;
            }
            if (x >= 100) {
                return 30;
            } else {
                return 0;
            }
        }
        //危险货物
        if(type.equals("Dangerous")) {
            if (x > 0 && x < 20) {
                return 80;
            }
            if (x >= 20 && x < 50) {
                return 50;
            }
            if (x >= 50 && x < 100) {
                return 30;
            }
            if (x >= 100) {
                return 20;
            } else {
                return 0;
            }
        }
        return 0;
    }
}
第二次的设计时我发现了第一次设计的代码的缺陷在题目的要求上首先修改了getRates方法从而可以达到题目的要求 然后我修改了getmoney方法,使其更加简便,合理利用到了getRates方法,而且通过这些修改使得我在设计Order类中的show方法时能够更好的利用Computeall方法。
  1. 踩坑点二
    在做第一次作业时没有注意输入超重时输出时的输出格式导致输出格式错误
  2. 踩坑点三
    在设计正确输出时的order类中的show方法时并未理解输出时输出中的总重量计算是计费重量而不是实际重量导致多次修改代码无果,最后在理解后才得到的输出正确的结果

四,改进建议

  1. 在遇到困难时的必要情况下可以寻求他人版主,不要自己死钻研。
  2. 如果在多次修改代码后依旧输出的结果错误可以换个想法,看看是不是别的细节自己忽略的导致输出的结果有误。
  3. 在类的设计时需要考虑的不仅仅是如何完成这个类需要发挥的作用,还需要考虑在别的类调用这个类的方法时,能不能合理的调用,会不会有问题,总之就是在设计类时还需要考虑设计的类与其他类之间的关系。

五,总结
对个人的总结

  1. 对于各个原则的理解还不够深入,需要继续学习
  2. 对于类的设计能力还是不够,需要继续增强相关方面的学习

对作业的改进建议

  1. 需要输出的容易起争议的数据进行标注,如我需要输出总重量,是输出计费总重量还是实际总重量。
  2. 对于给出的样例更加严格一点,需要达到题目的各个要求才能获得样例的输出,这样就不会出现设计出的代码对于样例可以正确输出但是对于测试点却还是有错误
posted @ 2025-05-24 11:07  kiroty  阅读(37)  评论(0)    收藏  举报