第二次blog大作业分析

前言

第二次blog大作业主要围绕航空货运管理系统展开,相较上一次的电梯分析,逻辑层面简单了不少,得分情况也比上一次理想。

一、需求分析

第一题(第八次pta练习)

1.核心功能

输入客户信息(编号、姓名、电话、地址)、货物信息(数量、编号、名称、尺寸、重量)、航班信息(航班号、起降机场、日期、最大载重量)、订单信息(订单号、日期、收发件人信息)。
计算订单总重量,判断是否超过航班剩余载重量(初始剩余载重量等于最大载重量,假设每单直接扣除重量,不考虑多订单累计)。

2.计算货物运费:根据货物重量计费,费率未明确给出(需假设或从样例反推,如样例 1 中发电机 80kg 运费 2000 元,费率为 25 元 /kg;信号发生器 45kg 运费 1350 元,费率 30 元 /kg,可能隐含不同货物类型对应不同费率,但题目未说明,可能默认按固定规则或样例硬编码)。
微信支付金额为运费总和(样例中 2000+1350=3350)。

3.输入输出特点
输入字段固定,货物信息按数量重复输入。
输出需格式化展示订单信息、总重量、支付金额和货物明细,数值保留 1 位小数。

第二题(第九次pta作业)

1.核心功能扩展
新增客户类型(Individual/Corporate)和货物类型(Normal/Expedite/Dangerous)。
新增支付方式(Wechat/ALiPay/Cash),不同支付方式可能影响费用(如样例 2 中支付宝支付金额为 3200+2250=5450?但样例输出为 4360,可能存在费率调整,需结合货物类型计算费率,如 Expedite 类型货物费率更高)。

2.费率逻辑更复杂:需根据货物类型(如 Expedite)和客户类型(如 Corporate)确定计费费率(样例 2 中发电机 80kg 运费 3200 元,费率 40 元 /kg;信号发生器 45kg 运费 2250 元,费率 50 元 /kg,可能 Expedite 类型费率为 Normal 的 1.5 倍或其他规则)。

3.输入输出特点
输入字段增加客户类型、货物类型、支付方式,逻辑分支更多。
输出需根据支付方式显示对应名称(如 “支付宝支付金额”),费用计算需结合多维度条件。

二、难度等级

第一题:中等难度。重点在于基础类设计和数据流程整合,业务逻辑相对直接,适合巩固面向对象基础(类封装、数据传递)。

第二题:中高难度。需处理多维度条件逻辑(客户类型 + 货物类型影响费率),可能需要策略模式或工厂模式解耦,考验代码结构设计和扩展性。同时,输入验证和枚举处理增加了细节复杂度。

第一题主要情况

1.题目

航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明参看说明文件。
OO第九周作业题目说明.pdf

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

客户编号
客户姓名
客户电话
客户地址
运送货物数量
[货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为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位小数。

输入样例:
在这里给出一组输入。例如:

10001
郭靖
13807911234
南昌航空大学
2
101
发电机
80
60
40
80
102
信号发生器
55
70
60
45
MU1234
昌北国际机场
大兴国际机场
2025-04-22
1000
900001
2025-04-22
南昌大学
洪七公
18907912325
北京大学
黄药师
13607912546
输出样例:
在这里给出相应的输出。例如:

客户:郭靖(13807911234)订单信息如下:

航班号:MU1234
订单号:900001
订单日期:2025-04-22
发件人姓名:洪七公
发件人电话:18907912325
发件人地址:南昌大学
收件人姓名:黄药师
收件人电话:13607912546
收件人地址:北京大学
订单总重量(kg):125.0
微信支付金额:3350.0

货物明细如下:

明细编号 货物名称 计费重量 计费费率 应交运费
1 发电机 80.0 25.0 2000.0
2 信号发生器 45.0 30.0 1350.0

2.分析类图

3.源代码

点击查看代码
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

class Customer {
    private int id;
    private String name;
    private String phone;
    private String address;

    public Customer(int id, String name, String phone, String address) {
        this.id = id;
        this.name = name;
        this.phone = phone;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }

    public String getAddress() {
        return address;
    }
}

class Goods {
    private int id;
    private String name;
    private double width;
    private double length;
    private double height;
    private double weight;

    public Goods(int id, String name, double width, double length, double height, double weight) {
        this.id = id;
        this.name = name;
        this.width = width;
        this.length = length;
        this.height = height;
        this.weight = weight;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public double getWidth() {
        return width;
    }

    public double getLength() {
        return length;
    }

    public double getHeight() {
        return height;
    }

    public double getWeight() {
        return weight;
    }

    public double calculateVolumeWeight() {
        return (width * length * height) / 6000;
    }

    public double getChargeableWeight() {
        return Math.max(weight, calculateVolumeWeight());
    }

    public double getRate() {
        double chargeableWeight = getChargeableWeight();
        if (chargeableWeight < 20) {
            return 35;
        } else if (chargeableWeight < 50) {
            return 30;
        } else if (chargeableWeight < 100) {
            return 25;
        } else {
            return 15;
        }
    }

    public double calculateShippingFee() {
        return getChargeableWeight() * getRate();
    }
}

class Flight {
    private String flightNumber;
    private String departureAirport;
    private String arrivalAirport;
    private String flightDate;
    private double maxLoadCapacity;
    private double remainingLoadCapacity;

    public Flight(String flightNumber, String departureAirport, String arrivalAirport, String flightDate, double maxLoadCapacity) {
        this.flightNumber = flightNumber;
        this.departureAirport = departureAirport;
        this.arrivalAirport = arrivalAirport;
        this.flightDate = flightDate;
        this.maxLoadCapacity = maxLoadCapacity;
        this.remainingLoadCapacity = maxLoadCapacity;
    }

    public String getFlightNumber() {
        return flightNumber;
    }

    public String getDepartureAirport() {
        return departureAirport;
    }

    public String getArrivalAirport() {
        return arrivalAirport;
    }

    public String getFlightDate() {
        return flightDate;
    }

    public double getMaxLoadCapacity() {
        return maxLoadCapacity;
    }

    public double getRemainingLoadCapacity() {
        return remainingLoadCapacity;
    }

    public boolean canCarryOrder(double totalWeight) {
        return remainingLoadCapacity >= totalWeight;
    }

    public void updateRemainingLoadCapacity(double totalWeight) {
        remainingLoadCapacity -= totalWeight;
    }
}

class Order {
    private int id;
    private String orderDate;
    private String senderAddress;
    private String senderName;
    private String senderPhone;
    private String recipientAddress;
    private String recipientName;
    private String recipientPhone;
    private List<Goods> goodsList;
    private Customer customer;
    private Flight flight;

    public Order(int id, String orderDate, String senderAddress, String senderName, String senderPhone,
                 String recipientAddress, String recipientName, String recipientPhone,
                 List<Goods> goodsList, Customer customer, Flight flight) {
        this.id = id;
        this.orderDate = orderDate;
        this.senderAddress = senderAddress;
        this.senderName = senderName;
        this.senderPhone = senderPhone;
        this.recipientAddress = recipientAddress;
        this.recipientName = recipientName;
        this.recipientPhone = recipientPhone;
        this.goodsList = goodsList;
        this.customer = customer;
        this.flight = flight;
    }

    public int getId() {
        return id;
    }

    public String getOrderDate() {
        return orderDate;
    }

    public String getSenderAddress() {
        return senderAddress;
    }

    public String getSenderName() {
        return senderName;
    }

    public String getSenderPhone() {
        return senderPhone;
    }

    public String getRecipientAddress() {
        return recipientAddress;
    }

    public String getRecipientName() {
        return recipientName;
    }

    public String getRecipientPhone() {
        return recipientPhone;
    }

    public List<Goods> getGoodsList() {
        return goodsList;
    }

    public Customer getCustomer() {
        return customer;
    }

    public Flight getFlight() {
        return flight;
    }

    public double calculateTotalWeight() {
        double totalWeight = 0;
        for (Goods goods : goodsList) {
            totalWeight += goods.getChargeableWeight();
        }
        return totalWeight;
    }

    public double calculateTotalShippingFee() {
        double totalShippingFee = 0;
        for (Goods goods : goodsList) {
            totalShippingFee += goods.calculateShippingFee();
        }
        return totalShippingFee;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int customerId = scanner.nextInt();
        scanner.nextLine();
        String customerName = scanner.nextLine();
        String customerPhone = scanner.nextLine();
        String customerAddress = scanner.nextLine();
        Customer customer = new Customer(customerId, customerName, customerPhone, customerAddress);

        int goodsCount = scanner.nextInt();
        List<Goods> goodsList = new ArrayList<>();
        for (int i = 0; i < goodsCount; i++) {
            int goodsId = scanner.nextInt();
            scanner.nextLine();
            String goodsName = scanner.nextLine();
            double width = scanner.nextDouble();
            double length = scanner.nextDouble();
            double height = scanner.nextDouble();
            double weight = scanner.nextDouble();
            Goods goods = new Goods(goodsId, goodsName, width, length, height, weight);
            goodsList.add(goods);
        }

        String flightNumber = scanner.next();
        scanner.nextLine();
        String departureAirport = scanner.nextLine();
        String arrivalAirport = scanner.nextLine();
        String flightDate = scanner.nextLine();
        double maxLoadCapacity = scanner.nextDouble();
        Flight flight = new Flight(flightNumber, departureAirport, arrivalAirport, flightDate, maxLoadCapacity);

        int orderId = scanner.nextInt();
        scanner.nextLine();
        String orderDate = scanner.nextLine();
        String senderAddress = scanner.nextLine();
        String senderName = scanner.nextLine();
        String senderPhone = scanner.nextLine();
        String recipientAddress = scanner.nextLine();
        String recipientName = scanner.nextLine();
        String recipientPhone = scanner.nextLine();
        Order order = new Order(orderId, orderDate, senderAddress, senderName, senderPhone,
                recipientAddress, recipientName, recipientPhone, goodsList, customer, flight);

        double totalWeight = order.calculateTotalWeight();
        if (!flight.canCarryOrder(totalWeight)) {
            System.out.printf("The flight with flight number: %s has exceeded its load capacity and cannot carry the order.\n", flight.getFlightNumber());
        } else {
            flight.updateRemainingLoadCapacity(totalWeight);
            System.out.printf("客户:%s(%s)订单信息如下:\n", order.getCustomer().getName(), order.getCustomer().getPhone());
            System.out.println("-----------------------------------------");
            System.out.printf("航班号:%s\n", order.getFlight().getFlightNumber());
            System.out.printf("订单号:%d\n", order.getId());
            System.out.printf("订单日期:%s\n", order.getOrderDate());
            System.out.printf("发件人姓名:%s\n", order.getSenderName());
            System.out.printf("发件人电话:%s\n", order.getSenderPhone());
            System.out.printf("发件人地址:%s\n", order.getSenderAddress());
            System.out.printf("收件人姓名:%s\n", order.getRecipientName());
            System.out.printf("收件人电话:%s\n", order.getRecipientPhone());
            System.out.printf("收件人地址:%s\n", order.getRecipientAddress());
            System.out.printf("订单总重量(kg):%.1f\n", totalWeight);
            System.out.printf("微信支付金额:%.1f\n", order.calculateTotalShippingFee());

            System.out.println("\n货物明细如下:");
            System.out.println("-----------------------------------------");
            System.out.println("明细编号\t货物名称\t计费重量\t计费费率\t应交运费");
            List<Goods> goods = order.getGoodsList();
            for (int i = 0; i < goods.size(); i++) {
                Goods good = goods.get(i);
                System.out.printf("%d\t%s\t%.1f\t%.1f\t%.1f\n", i + 1, good.getName(), good.getChargeableWeight(), good.getRate(), good.calculateShippingFee());
            }
        }
        scanner.close();
    }
}

4.代码分析

(1)代码规模
总行数:317 行,相较于 638 行的代码,规模更小。
语句数:205 个,代码量处于适中水平。
(2)代码复杂性
最大复杂度:5,相比之前 12 的最大复杂度,这个值较低,说明代码中方法逻辑相对简单。
平均复杂度:1.15,远低于之前的 2.06 ,表明整体方法复杂度控制得较好。
最复杂方法:Goods.getRate () ,复杂度为 5 ,相比之前最复杂方法复杂度低,不过仍需关注其逻辑是否可进一步优化。
(3)代码结构
最大复杂度:同代码复杂性中的最大复杂度,为 5 ,说明代码结构方面没有特别复杂的嵌套或逻辑。
平均复杂度:1.15,整体方法平均复杂度低,代码结构较清晰。
最复杂方法:Goods.getRate () ,该方法可能存在一定结构优化空间。
(4)代码注释
含注释行的百分比:0.0% ,与之前 18.8% 相比,注释严重缺乏,会降低代码可读性,不利于后续维护和他人理解代码。
(5)代码块深度
最大代码块深度:3,比之前的 7 小很多,表明代码中嵌套结构较浅。
平均代码块深度:1.74,相对较低,说明代码整体嵌套程度不高,易于理解和维护。
(6)分支和方法调用
分支语句百分比:4.4% ,相较于之前的 19.3% 低很多,代码中的分支逻辑很少,降低了代码复杂性。
方法调用语句数:55 个,方法调用不算频繁,代码耦合度相对较低。
(7)最复杂方法分析
Goods.getRate():复杂度为 5,语句数为 9,最大深度为 3,调用数为 1 。该方法相对复杂,可能由于其内部存在条件判断等逻辑来确定费率,可进一步审视优化。

第二题
1题目

航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明参看说明文件。
OO第九周作业题目说明.pdf

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

客户编号
客户姓名
客户电话
客户地址
运送货物数量
[货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为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位小数。

输入样例:
在这里给出一组输入。例如:

10001
郭靖
13807911234
南昌航空大学
2
101
发电机
80
60
40
80
102
信号发生器
55
70
60
45
MU1234
昌北国际机场
大兴国际机场
2025-04-22
1000
900001
2025-04-22
南昌大学
洪七公
18907912325
北京大学
黄药师
13607912546
输出样例:
在这里给出相应的输出。例如:

客户:郭靖(13807911234)订单信息如下:

航班号:MU1234
订单号:900001
订单日期:2025-04-22
发件人姓名:洪七公
发件人电话:18907912325
发件人地址:南昌大学
收件人姓名:黄药师
收件人电话:13607912546
收件人地址:北京大学
订单总重量(kg):125.0
微信支付金额:3350.0

货物明细如下:

明细编号 货物名称 计费重量 计费费率 应交运费
1 发电机 80.0 25.0 2000.0
2 信号发生器 45.0 30.0 1350.0

2.分析类图

3.代码

点击查看代码
import java.util.*;
import java.text.SimpleDateFormat;

// 客户类
abstract class Customer {
    String id, name, phone, address;

    public Customer(String id, String name, String phone, String address) {
        this.id = id;
        this.name = name;
        this.phone = phone;
        this.address = address;
    }
}

// 个人客户
class IndividualCustomer extends Customer {
    public IndividualCustomer(String id, String name, String phone, String address) {
        super(id, name, phone, address);
    }
}

// 企业客户
class CorporateCustomer extends Customer {
    public CorporateCustomer(String id, String name, String phone, String address) {
        super(id, name, phone, address);
    }
}

// 货物类(抽象)
abstract class Cargo {
    String cargoId, name;
    double width, length, height, weight;

    public Cargo(String cargoId, String name, double width, double length, double height, double weight) {
        this.cargoId = cargoId;
        this.name = name;
        this.width = width;
        this.length = length;
        this.height = height;
        this.weight = weight;
    }

    // 计费重量(可以重写)
    public double getChargeWeight() {
        return weight;
    }

    // 计费费率(抽象)
    public abstract double getRate();
}

// 普通货物
class NormalCargo extends Cargo {
    public NormalCargo(String cargoId, String name, double width, double length, double height, double weight) {
        super(cargoId, name, width, length, height, weight);
    }

    @Override
    public double getRate() {
        return 40.0;
    }
}

// 加急货物
class ExpediteCargo extends Cargo {
    public ExpediteCargo(String cargoId, String name, double width, double length, double height, double weight) {
        super(cargoId, name, width, length, height, weight);
    }

    @Override
    public double getRate() {
        return 50.0;
    }
}

// 危险货物
class DangerousCargo extends Cargo {
    public DangerousCargo(String cargoId, String name, double width, double length, double height, double weight) {
        super(cargoId, name, width, length, height, weight);
    }

    @Override
    public double getRate() {
        return 60.0;
    }
}

// 航班类
class Flight {
    String flightNo, departAirport, arriveAirport, date;
    double maxLoad;
    double currentLoad = 0;

    public Flight(String flightNo, String departAirport, String arriveAirport, String date, double maxLoad) {
        this.flightNo = flightNo;
        this.departAirport = departAirport;
        this.arriveAirport = arriveAirport;
        this.date = date;
        this.maxLoad = maxLoad;
    }

    public boolean canCarry(double weight) {
        return currentLoad + weight <= maxLoad;
    }

    public void addLoad(double weight) {
        currentLoad += weight;
    }
}

// 订单类
class Order {
    String orderNo, orderDate;
    Customer sender, receiver;
    Flight flight;
    List<Cargo> cargoList;
    String paymentMethod; // Wechat/Alipay/Cash

    public Order(String orderNo, String orderDate, Customer sender, Customer receiver,
                 Flight flight, List<Cargo> cargoList, String paymentMethod) {
        this.orderNo = orderNo;
        this.orderDate = orderDate;
        this.sender = sender;
        this.receiver = receiver;
        this.flight = flight;
        this.cargoList = cargoList;
        this.paymentMethod = paymentMethod;
    }

    public double getTotalWeight() {
        double sum = 0;
        for (Cargo c : cargoList) {
            sum += c.getChargeWeight();
        }
        return sum;
    }

    public double getTotalFee() {
        double sum = 0;
        for (Cargo c : cargoList) {
            sum += c.getChargeWeight() * c.getRate();
        }
        return sum;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        try {
            // ---------------------------------------------------------------------
            // 读取客户信息
            String customerType = sc.nextLine().trim();
            if (!customerType.equals("Individual") && !customerType.equals("Corporate")) {
                throw new IllegalArgumentException("Invalid customer type: " + customerType);
            }

            String customerId = sc.nextLine().trim();
            String customerName = sc.nextLine().trim();
            String customerPhone = sc.nextLine().trim();
            String customerAddress = sc.nextLine().trim();

            Customer customer;
            if (customerType.equalsIgnoreCase("Individual")) {
                customer = new IndividualCustomer(customerId, customerName, customerPhone, customerAddress);
            } else {
                customer = new CorporateCustomer(customerId, customerName, customerPhone, customerAddress);
            }

            // 货物信息
            String cargoType = sc.nextLine().trim();
            if (!cargoType.equals("Normal") && !cargoType.equals("Expedite") && !cargoType.equals("Dangerous")) {
                throw new IllegalArgumentException("Invalid cargo type: " + cargoType);
            }

            int cargoCount;
            try {
                cargoCount = Integer.parseInt(sc.nextLine().trim());
                if (cargoCount <= 0) {
                    throw new IllegalArgumentException("Cargo count must be positive: " + cargoCount);
                }
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Invalid cargo count format");
            }

            List<Cargo> cargoList = new ArrayList<>();
            double totalWeight = 0;

            for (int i = 0; i < cargoCount; i++) {
                String cargoId = sc.nextLine().trim();
                String cargoName = sc.nextLine().trim();
                double width, length, height, weight;

                try {
                    width = Double.parseDouble(sc.nextLine().trim());
                    length = Double.parseDouble(sc.nextLine().trim());
                    height = Double.parseDouble(sc.nextLine().trim());
                    weight = Double.parseDouble(sc.nextLine().trim());
                    if (width <= 0 || length <= 0 || height <= 0 || weight <= 0) {
                        throw new IllegalArgumentException("Dimensions and weight must be positive");
                    }
                } catch (NumberFormatException e) {
                    throw new IllegalArgumentException("Invalid dimension or weight format");
                }

                Cargo cargo;
                switch (cargoType) {
                    case "Normal":
                        cargo = new NormalCargo(cargoId, cargoName, width, length, height, weight);
                        break;
                    case "Expedite":
                        cargo = new ExpediteCargo(cargoId, cargoName, width, length, height, weight);
                        break;
                    case "Dangerous":
                        cargo = new DangerousCargo(cargoId, cargoName, width, length, height, weight);
                        break;
                    default:
                        throw new IllegalArgumentException("Invalid cargo type: " + cargoType);
                }

                cargoList.add(cargo);
                totalWeight += cargo.getChargeWeight();
            }

            // 航班信息
            String flightNo = sc.nextLine().trim();
            String departAirport = sc.nextLine().trim();
            String arriveAirport = sc.nextLine().trim();
            String flightDate = sc.nextLine().trim();

            double maxLoad;
            try {
                maxLoad = Double.parseDouble(sc.nextLine().trim());
                if (maxLoad <= 0) {
                    throw new IllegalArgumentException("Flight max load must be positive: " + maxLoad);
                }
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Invalid flight max load format");
            }

            Flight flight = new Flight(flightNo, departAirport, arriveAirport, flightDate, maxLoad);

            // 订单信息
            String orderNo = sc.nextLine().trim();
            String orderDate = sc.nextLine().trim();

            String senderName = sc.nextLine().trim();
            String senderPhone = sc.nextLine().trim();
            String senderAddress = sc.nextLine().trim();
            Customer sender = new IndividualCustomer("Sender", senderName, senderPhone, senderAddress);

            String receiverName = sc.nextLine().trim();
            String receiverPhone = sc.nextLine().trim();
            String receiverAddress = sc.nextLine().trim();
            Customer receiver = new IndividualCustomer("Receiver", receiverName, receiverPhone, receiverAddress);

            String paymentMethod = sc.nextLine().trim();
            if (!paymentMethod.equals("Wechat") && !paymentMethod.equals("ALiPay") && !paymentMethod.equals("Cash")) {
                throw new IllegalArgumentException("Invalid payment method: " + paymentMethod);
            }

            // 创建订单
            Order order = new Order(orderNo, orderDate, sender, receiver, flight, cargoList, paymentMethod);

            // 判断是否超载
            if (order.getTotalWeight() > flight.maxLoad) {
                System.out.println("The flight with flight number:" + flight.flightNo + " has exceeded its load capacity and cannot carry the order.");
                return;
            } else {
                // 更新航班剩余载重
                flight.addLoad(order.getTotalWeight());
                // 输出信息
                printOrderDetails(order);
            }
        } catch (IllegalArgumentException e) {
            System.out.println("Invalid input: " + e.getMessage());
        } finally {
            sc.close();
        }
    }
static void printOrderDetails(Order order) {
    // 客户:姓名(电话)订单信息如下:
    System.out.println("客户:" + order.receiver.name + "(" + order.receiver.phone + ")订单信息如下:");
    System.out.println("-----------------------------------------");
    System.out.println("航班号:" + order.flight.flightNo);
    System.out.println("订单号:" + order.orderNo);
    System.out.println("订单日期:" + order.orderDate);
    System.out.println("发件人姓名:" + order.sender.name);
    System.out.println("发件人电话:" + order.sender.phone);
    System.out.println("发件人地址:" + order.sender.address);
    System.out.println("收件人姓名:" + order.receiver.name);
    System.out.println("收件人电话:" + order.receiver.phone);
    System.out.println("收件人地址:" + order.receiver.address);
    System.out.printf("订单总重量(kg):%.1f\n", order.getTotalWeight());
    
    // 支付方式
    String payMethodStr = "";
    switch (order.paymentMethod) {
        case "Wechat": payMethodStr = "微信"; break;
        case "ALiPay": payMethodStr = "支付宝"; break;
        case "Cash": payMethodStr = "现金"; break;
    }
    System.out.printf("%s支付金额:%.1f\n", payMethodStr, order.getTotalFee());
    
    // 货物明细
    System.out.println("\n货物明细如下:");
    System.out.println("-----------------------------------------");
    System.out.println("明细编号    货物名称    计费重量    计费费率    应交运费");
    for (int i = 0; i < order.cargoList.size(); i++) {
        Cargo cargo = order.cargoList.get(i);
        System.out.printf("%-10d %-12s %-10.1f %-10.1f %-10.1f\n",
                i + 1,
                cargo.name,
                cargo.getChargeWeight(),
                cargo.getRate(),
                cargo.getChargeWeight() * cargo.getRate());
    }
}
}

四.代码分析

(1)代码规模
总行数:321 行,代码量相对适中。
语句数:182 个,表明代码中的执行语句数量不算少,反映出一定的功能丰富度。
(2)代码复杂性
最大复杂度:28 ,这个值相当高,说明存在极为复杂的方法,如 Main.main() 方法复杂度达到 28 ,意味着其内部逻辑嵌套、分支、条件判断等操作繁多,理解和维护难度大。
平均复杂度:5.67 ,明显高于一般较为简洁代码的平均复杂度,说明整体代码方法复杂度偏高,可能多处存在逻辑复杂的情况。
最复杂方法:Main.main() ,复杂度为 28 ,语句数 90 ,最大深度 6 ,调用数 45 。该方法涉及大量输入验证、业务逻辑处理、对象创建和流程控制,是代码中最需要关注优化的部分。
(3)代码结构
最大复杂度:同代码复杂性中的最大复杂度,为 28 ,表明代码中存在结构非常复杂的部分。
平均复杂度:5.67 ,说明整体代码结构上方法复杂度较高,可能存在较多不必要的嵌套、复杂的条件组合等情况。
最复杂方法:Main.main() ,此方法在代码结构上也最为复杂,需要进一步梳理逻辑、拆分功能以优化结构。
(4)代码注释
含注释行的百分比:7.2% ,注释比例较低,不利于代码的可读性和可维护性,他人阅读和理解代码逻辑会存在一定困难。
(5)代码块深度
最大代码块深度:6 ,表示代码中存在嵌套层次较深的结构,可能存在多层循环、条件嵌套等情况,增加了代码理解难度。
平均代码块深度:2.29 ,整体代码块深度处于中等偏上水平,说明代码中存在一定程度的嵌套结构,需要关注是否存在可以优化的冗余嵌套。
(6)分支和方法调用
分支语句百分比:15.4% ,代码中分支逻辑占比不算低,过多的分支可能使代码逻辑变得复杂和难以跟踪。
方法调用语句数:62 个 ,方法调用较为频繁,这可能会影响代码的耦合度和性能,需要检查方法调用是否合理,是否存在可以合并或优化的调用逻辑。
(7)最复杂方法分析
Main.main():复杂度 28 ,语句数 90 ,最大深度 6 ,调用数 45 。此方法承担了大量工作,包括输入读取、验证,各类对象创建和业务流程控制等。可通过将不同功能模块拆分成独立方法,减少内部逻辑复杂性,提高代码的可读性和可维护性。
Main.printOrderDetails():复杂度 2 ,语句数 10 ,最大深度 3 ,调用数 7 。虽然复杂度相对较低,但也可检查其内部逻辑和调用是否可以进一步优化,以减少代码冗余。

四.踩坑心得
第一题

一开始时答案出现了多种错误

修改过后能够做到正常测试通过

在编写航空货运管理系统代码的过程中,我积累了不少宝贵经验。
1.起初,我没太重视输入验证,第一版代码里对客户类型、支付方式等输入都没做类型检查,货物尺寸、重量等数值也没验证范围。这就导致一旦输入不合法数据,程序很可能出现运行时异常。后来我意识到,对用户输入必须严格把关,要全面检查类型合法性、数值范围、格式匹配等,不然就会留下隐患。

2.在设计类结构和业务逻辑时,我一开始没做好抽象和继承,像 Goods.getRate() 方法用多层 if - else 判断费率,逻辑复杂又难扩展。这让我明白,要遵循面向对象设计原则,用多态来替代复杂的条件判断,比如把 Customer 和 Cargo 设计成抽象类,通过子类实现差异化行为,这样代码扩展性和维护性都会大大提高。

3.对于状态管理,第一版 Flight 类的载重管理依赖外部调用去更新剩余载重,很容易遗漏操作,导致状态不一致。后来我把状态管理封装在类内部,通过特定方法自动更新,减少了外部依赖,降低出错风险。

4.异常处理方面,第一版代码对输入格式错误没做处理,程序遇到非数字输入等情况就可能崩溃。我这才知道,对用户输入和涉及外部资源的操作,都得做好异常处理,给出明确错误提示,方便调试和维护。

5.代码结构上,第一版比较扁平,功能都堆在 main 方法里,可读性和可维护性差。后来我把订单信息输出等逻辑封装成独立方法,还通过抽象类和继承分离不同功能,遵循单一职责原则,让代码结构更清晰。

总之,通过这两次代码编写,我深刻认识到在开发中要注重输入验证、合理运用面向对象设计原则、做好状态管理和异常处理,以及优化代码结构,这样才能编写出健壮、易维护和可扩展的程序。

第二题


第一次只能做到部分输出正确


第二次情况已经好了很多

总结
优化点
1.类型系统优化:在第一版代码里,我使用抽象类来定义 Customer 和 Cargo,实现多态。但到了第二版,我进一步引入了接口(比如 Cargo 接口和 PaymentMethod 接口)。这让代码的类型结构更清晰,也符合面向接口编程的思想。就像不同的货物类型实现 Cargo 接口,各自实现计费重量和费率计算逻辑,更方便后续添加新的货物类型,代码扩展性大大增强。

2.日期处理优化:第一版我用 LocalDate 处理日期,这是个不错的现代日期处理方式。但在第二版,我简化了日期处理,直接用字符串存储日期,减少了日期格式化等操作,代码变得更简洁,也降低了出错的可能,毕竟日期格式处理很容易出问题。

3.代码结构优化:第一版代码里,像 Order 类的方法和属性布局有点混乱。到了第二版,我把属性和方法的定义顺序调整得更合理,属性集中定义,然后是 setter 方法,最后是计算和打印方法,这样代码的可读性提高了很多,我自己再看代码或者别人接手维护时都更轻松。

4.代码复用性提升:第一版中有些计算逻辑在不同类中重复出现,比如计费重量的计算。在第二版,我把这些重复逻辑提取到接口实现中,避免了重复代码,代码的维护性更好。如果要修改计费重量的计算规则,只需要在一处修改就行。

5.异常处理和输入验证:虽然两版代码在这方面都有涉及,但第二版我对输入验证的逻辑更严谨了。比如在获取用户输入时,对每一项输入都做了更细致的判断,确保输入符合预期格式,像货物数量必须是整数,重量等数值必须是正数等,这能有效避免程序因为非法输入而崩溃。

踩坑心得
1.过度设计风险:在第一版代码里,我为了追求多态和扩展性,使用抽象类和继承层次有点复杂。到第二版,我意识到有时候简单直接的设计更好。比如引入接口后,既实现了多态需求,又不会让代码结构过于复杂。以后设计代码时,我得平衡好扩展性和代码复杂度,不能盲目追求复杂的设计模式。

2.日期处理谨慎选择:第一版用 LocalDate 虽然功能强大,但涉及到日期格式化等操作,容易出错。第二版用字符串处理简单场景下的日期,更简洁明了。这让我明白要根据实际需求选择合适的日期处理方式,不是越高级的工具就越好,合适才是关键。

3.代码可读性很重要:第一版代码结构不够清晰,我自己回头看代码都得花不少时间理解。第二版调整结构后,代码可读性提升明显。以后写代码,我一开始就得注重代码结构和布局,让代码逻辑清晰,方便自己和他人阅读维护。

4.重复代码零容忍:第一版重复代码给我修改和维护带来不少麻烦。第二版消除重复代码后,代码简洁又易于维护。以后写代码,只要发现有重复逻辑,我就得及时提取成公共方法或者合理利用接口、继承等机制复用代码。

5.输入验证要全面:第一版输入验证不够细致,可能会让程序在运行时出问题。第二版加强输入验证后,程序健壮性提高了。以后开发中,我得对所有用户输入进行严格验证,不能偷懒,这是保证程序稳定运行的基础。

五.总结

1.设计权衡:别让过度设计 “拖累” 代码
我曾在设计类结构时,为了追求 “高扩展性” 而引入多层继承和抽象类,结果导致代码变得复杂难懂。比如最初把所有客户和货物的细节都塞进抽象类,反而让子类变得冗余。后来我明白,设计模式是工具而非目标—— 在使用抽象类、接口或策略模式时,必须先判断当前需求是否真的需要这么复杂的结构。比如第二版代码中,我用接口定义核心行为(如Cargo.getRate()),既保持了扩展性,又避免了过度抽象,让代码简洁易读。平衡复杂度永远是关键,能简单实现的功能,就别用复杂的设计 “画蛇添足”。

2.技术选型:合适的才是最好的
在处理日期时,我一开始盲目追求 “现代化”,用LocalDate处理所有时间逻辑,结果发现用户输入的日期格式不固定,需要额外写大量校验和转换代码,反而容易出错。后来换成字符串存储简单场景下的日期,代码瞬间清爽了很多。这让我意识到,技术选型不能只看 “高级”,更要贴合实际需求。比如在输入验证中,用简单的if-else判断用户类型是否合法,比引入复杂的正则表达式更直接有效。选择技术方案时,要多问自己:这个工具能解决实际问题吗?会不会增加额外成本?

3.代码可读性:从第一天起就 “写让别人能看懂的代码”
第一版代码的main方法里,输入读取和逻辑混杂在一起,我自己隔了一周再看都觉得混乱。后来我把输入验证、对象创建、输出逻辑拆分成独立方法(如printOrderDetails),并调整类中属性和方法的顺序(先定义属性,再写方法),代码结构立刻清晰了。可读性不是 “锦上添花”,而是决定代码生命周期的关键。现在我写代码时,会刻意用清晰的变量名(如chargeableWeight而非简写cw),并通过空行、注释分隔逻辑块,让未来的自己能快速理解。

4.重复代码处理:看见重复,立刻 “消灭”
在第一版货物费率计算中,NormalCargo、ExpediteCargo都重复写了 “重量 - 费率” 的条件判断,修改时必须改多处,特别容易漏改。后来我把公共逻辑提取到接口的默认方法中,或者通过抽象类实现部分通用逻辑,代码量减少了一半,维护起来也省心。重复代码是 “技术债务”,会越积越多。现在只要发现两段代码逻辑相似,我就会立刻提取成公共方法或工具类,比如将计算体积重量的公式封装到Cargo接口的getChargeableWeight中,所有货物类型直接复用。

5.输入验证意识:永远假设用户会输入 “非法数据”
我曾在测试中遇到用户输入负数重量,导致程序抛出NumberFormatException崩溃。这让我意识到,用户输入的每一个数据都可能是 “危险的”。现在我会对所有输入做严格校验:客户类型必须是指定枚举值、货物数量必须大于 0、重量和尺寸必须为正数,甚至用正则表达式校验电话号码格式。虽然这会增加一些代码量,但能避免 90% 以上的运行时错误。记住:程序的健壮性不取决于 “正常情况”,而取决于 “异常情况” 的处理是否完善。

这些心得都是从一次次调试和重构中总结出来的,现在回头看,代码质量的提升本质上是 “用简单方式解决复杂问题” 的思维转变。未来再开发类似系统时,我会更注重从需求出发,用 “刚刚好” 的设计和技术,写出既灵活又易维护的代码。

posted @ 2025-05-21 17:59  树花颂声  阅读(40)  评论(0)    收藏  举报