BLOG-NCHU_航空货运管理系统

NCHU_航空货运管理系统

前言

这两次关于航空货运管理系统的作业重点在于其中的类设计,要求符合面向对象程序设计原则,题目的核心逻辑较为简单,
对数据的处理也比较直接,但其难点是如何用合理的类设计来处理这些问题,最终得到理想的结果。
现在对题目本身进行一些叙述,航空货运在当今社会已经较为常见,他高效的运输速度,与强大的货运能力被许多的企业
推崇与应用,这样就会出现更多的订单,所以航空货运管理系统就显得格外重要。这两次的题目虽然只是一个简化版的管
理系统,但依旧可以体现面向对象编程技术在处理实际问题的优越性。

设计与分析

第一次题目分析

题目概述:

某航空公司“航空货运管理系统”中的空运费的计算涉及多个因素,通常包括

  • 货物重量/体积
  • 运输距离
  • 附加费用
  • 货物类型
  • 客户类型
  • 市场供需

本次作业主要考虑货物重量/体积

输入格式:

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

输出格式

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

货物明细如下:
-----------------------------------------
明细编号    货物名称    计费重量    计费费率    应交运费
1    ...
2    ...
  • 如果订单中货物重量超过
    航班剩余载重量,程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order.程序终止运行。

分析设计

类设计

  • 接口与抽象类
    Dayinable接口:定义了dayin()方法,用于打印信息。多个实体类(如 Customer、Sender、Geter 等)实现了该接口,体现了多态性。
    Payable接口:定义了getall()方法,用于计算总金额。支付相关类(Wechat、Ali)实现了该接口。
    Example抽象类:实现了 Dayinable 接口,作为多个实体类的父类,包含 ID 属性和相关方法。
    Pay抽象类:作为支付类的父类,体现支付方式多样性。
  • 数据实体类
    客户类(Customer)
    发件人(Sender)和收件人(Geter)
    货物类(Goods)
    航班类(Flight)
    订单类(Order)
    支付类(Wechat、Ali)
  • 业务逻辑处理
    订单管理类(Dindan)

关键方法设计

  • 计费重量计算
public double realweight(){
    double rw=(w*l*h)/6000;
    if(rw>weight){
        return rw;
    }
    else return weight;
}

在本题中,计费重量不一定与实际重量相同,它等于实际重量,与体积重量的较高值,用此方法进行对计费重量的计算。
(其中体积重量的计算公式为:体积重量(kg)= 货物体积(长×宽×高,单位:厘米)÷6000

  • 费率的计算
public double rate(){
    if(realweight()<20){
        return 35.0;
    }
    else if(realweight()>=20&&realweight()<50){
        return 30.0;
    }
    else if(realweight()>=50&&realweight()<100){
        return 25.0;
    }
    else return 15.0;
}

本题中不同的计费重量所对应的费率是不同的,他与计费重量的关系如下图:


用上面的方法求取实际的费率,用于计算实际运费。

  • 订单信息展示方法
public void show(){
    customer.dayin();
    System.out.println("-----------------------------------------");
    flight.dayin();
    order.dayin();
    sender.dayin();
    geter.dayin();
    System.out.printf("订单总重量(kg):%.1f\n", order.getall());
    wechat.dayin();
    System.out.print("\n");
    System.out.println("货物明细如下:");
    System.out.println("-----------------------------------------");
    System.out.printf("明细编号\t货物名称\t计费重量\t计费费率\t应交运费\n");
    int i=1;
    while(i<=order.getList().size()){
        System.out.print(i+"\t");
        order.getList().get(i-1).dayin();
        i++;
    }
}

本方法通过调用各个类的Dayin()方法,实现了对订单信息的展示,匹配了题目给出格式,得到正确的结果。

设计总结与分析

  • 面向对象设计原则的应用总结

抽象与多态:通过Dayinable接口和Example抽象类,实现了不同实例(客户、货物、航班等)的统一打印,提高了代码复用性。

接口隔离:Payable接口将计算总金额的行为抽象出来,使支付方式(微信、支付宝)具有扩展性

单一职责原则:核心计费规则将复杂的运费计算逻辑(体积重量、阶梯费率)封装在Goods类中

  • 缺点分析

在本次题目中,代码有大量的冗杂重复,如Customer、Sender、Geter类中有大量重复的属性(name、call、address),未抽象出公共父类,
同时在Wechat和Ali类中的getall()方法实现完全相同,未提取到父类Pay中,这些造成了代码的可读性大大下降,但在我下次的题目中,我做出了
一定的改进,使代码更加的精简。

SourceMonitor分析

从图中可见平均方法数为10,体现类中实现的方法过多,同时也缺少注释,代码可读性较低,其中平均复杂度与最大复杂度为异常数据(我也不知道为什么),
实际平均复杂度约为 1.5-2,最高复杂度为 5(用其他工具测出),总体复杂度较为正常。

类图

类图中体现了各个类之间的关系

第二次题目分析

题目概述

本次题目与上次题目大体相同,但是依旧有一定的改变,改变如下:

  • 订单类型增加:新增由普通(Normal)、加急(Expedite)、危险品(Dangerous)类型,不同类型对应的费率也会有所改变(具体改变下面有提)
  • 支付方式改变:可以支持不同的支付方式(在输入格式有体现)
  • 客户类型区分:区分个人和企业,分别享受9折和8折的优惠

输入格式

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

输出格式

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

货物明细如下:
-----------------------------------------
明细编号    货物名称    计费重量    计费费率    应交运费
1    ...
2    ...
  • 如果订单中货物重量超过航班剩余载重量,
    程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order.程序终止运行。

分析设计

类设计

本次的类设计相较上一次有所改变,改变如下:

  • Goods类的抽象化与子类分化
    Goods被设计为抽象类,将通用的属性和方法(如realweight()getmoney()dayin())抽象出来,
    同时分有NormalgoodsExpeditegoodsDangerousgoods 等具体子类继承,每个子类实现各自的rate()方法,
    实现不同类型货物费率计算的差异化

  • 支付类的调整
    Pay抽象类增加了Example customer,在计算总费用时会根据客户类型给予不同折扣 ,
    Wechat、Ali、Cash(新增)等支付子类继承该方法,以满足不同客户的优惠策略。

  • 新增Orderall类
    之前订单相关订单信息统计和展示逻辑在Order类中,现在将货物列表管理、总重量计算、货物明细展示等功能提取到Orderall类中,
    使Order类职责更单一,专注于订单整体信息的展示,提高了代码的内聚性。

关键方法的调整

  • rate()方法的更改
    新的运算逻辑:

    因为不同的货物类型有不同的计算方法,所以这个方法在子类中分别实现,以下是Normalgoods的对应方法:
public double rate(){
        if(realweight()<20){
            return 35.0;
        }
        else if(realweight()>=20&&realweight()<50){
            return 30.0;
        }
        else if(realweight()>=50&&realweight()<100){
            return 25.0;
        }
        else return 15.0;
    }
  • 支付金额计算方法更改
    由于不同用户的折扣力度不同,所以计算运费的方法也要进行修正:
public double getall(){
        double count=0;
        for(int i=0;i<orderall.getList().size();i++){
            count+=orderall.getList().get(i).getmoney();
        }
        if(customer.kind.equals("Individual")){
            return 0.9*count;
        }
        else{
            return 0.8*count;
        }
    }

除此之外其他部分有些许改变,但是大体不变,就不过多赘述。

设计总结与分析

  • 类结构优化
    将Goods类抽象化,衍生出Normalgoods、Expeditegoods、Dangerousgoods 等子类,使不同类型货物的费率计算规则各自独立实现

  • 职责分离
    新增Orderall类,将货物统计、总重量计算、货物展示等功能从Order类分离出来,
    这使得Order类专注于订单整体信息展示,Orderall类专注于对货物操作。

  • 仍存在的不足
    命名采用拼音的形式,这样不规范,对代码的可读性造成一定的影响,同时部分子类在一些逻辑上
    有相似之处,可以都抽象在父类中,使代码更加精简。

SourceMonitor分析


代码的语句数,分支数,深度都有所提升,这是因为题目复杂度提升(也办法啊),由分支数判断复杂度的数据依旧是错误的,
实际的复杂度为:最高复杂度为5,平均复杂度为1.5-2。总体上与第一次差不多。

类图


以上就为代码中类的关系

踩坑心得

关于换行符的吸收问题


这是由于在使用连续nextDouble()和nextLine()时,需用in.nextLine()吸收换行符,否则会导致数据与类型不匹配。

关于输出结构问题

这个坑纯属是失误,我以为输出货物详细信息使用空格分开,但是答案是错误的(改了我好久)

最后改了不下10几遍终于发现错误是分开是用 \t ,我真的服了.....

改进建议

  • 命名规范
    统一中英文命名:将拼音命名(如 dayin())改为英文(如 show())

  • 消除代码冗杂
    将Wechat、Ali、Cash中的重复代码移至父类 Pay
    新建Person类,将Customer、Sender、Receiver 中的公共属性可放至Person

  • 异常数据处理
    添加异常数据的处理与判断,使程序更加通用合理

总结

通过这两次的题目,我对面向对象程序设计原则有了更加深刻的理解。通过运用这些原则,使我的航空货运管理系统逻辑更加清晰,
代码更有条理,对后面的扩展性有极大的帮助,同时这次的题目集新加了抽象与接口,他们为后面众多类的管理起了巨大作用。

这次的两次作业同时也暴露了我许多的问题,如刚开始对接口意义理解不清,导致开始的设计逻辑有巨大错误,但在做题的过程中,
我慢慢体会到了接口的作用,这对我的编程能力有了巨大的提升

posted @ 2025-05-24 23:41  NTtowait  阅读(41)  评论(0)    收藏  举报