航空货运管理系统(继承与多态)

航空货运管理系统开发日志
一、需求分析阶段:从一团糟倒层层剖析
最开始盯着五个类头皮发麻,仔细分析,然后画出对应的类图之后才稍微有点思路。特别纠结费率的实现方式,后来发现其实只需要设计一个专门计算的ShippingCostCalculator,然后定义好接口就能搞定。
这是刚开始画的类图

二、类设计阶段

  1. ClientInfo类

class ClientInfo {
private String clientCategory;
private String clientIdentifier;
private String fullName;
private String contactNumber;
private String locationDetails;

public ClientInfo(String category, String id, String name, String phone, String address) {
    clientCategory = category;
    clientIdentifier = id;
    fullName = name;
    contactNumber = phone;
    locationDetails = address;
}

public String getFullName() { return fullName; }
public String getContactNumber() { return contactNumber; }
public String getClientCategory() { return clientCategory; }

}
刚开始把构造函数的私有变量搞反了,因为命名的时候没有注意,然后写完之后测试一下发现怎么改格式都不对,用测试用例看一下才发现两个名字是一样的,然后才搞好,浪费了很多时间
这是原来写错的代码
public ClientInfo(String category, String id, String name, String phone, String address) {
clientCategory = category;
clientIdentifier = id;
fullName = name;
contactNumber = id;
locationDetails = address;
}

  1. ShipmentItem类
    class ShipmentItem {
    private String itemCategory;
    private String itemIdentifier;
    private String productName;
    private double dimensionWidth;
    private double dimensionLength;
    private double dimensionHeight;
    private double measuredMass;

    public ShipmentItem(String category, String id, String name,
    double width, double length, double height, double weight) {
    itemCategory = category;
    itemIdentifier = id;
    productName = name;
    dimensionWidth = width;
    dimensionLength = length;
    dimensionHeight = height;
    measuredMass = weight;
    }

    public double computeVolumetricMass() {
    return Math.round(((dimensionLength * dimensionWidth * dimensionHeight) / 6000) * 10.0) / 10.0;
    }

    public double determineBillingMass() {
    return Math.round(Math.max(measuredMass, computeVolumetricMass()) * 10.0) / 10.0;
    }

    public String getProductName() { return productName; }
    public String getItemCategory() { return itemCategory; }
    }
    计算结果偏差,然后调整公式和取整方式来解决问题
    还有一些是上一次作业迭代做的
    对应了computeVolumetricMass()和determineBillingMass()的嵌套调用。当测试30x40x50cm的箱子时:
    // 初版计算
    public double computeVolumetricMass() {
    return (30 * 40 * 50)/6000; // 本该是10kg却算出1kg
    }
    原来Java把6000当作整数处理,就像超市结账时把"第二件半价"算成"第二件免费"。改成6000.0后才恢复正常。

  2. 最烧脑的ShippingCostCalculator
    三个费率表每个代表的都不一样,刚开始想要用一个函数统一表示,后面想了一下发现好麻烦,特别是三个信息都在变的时候,公式很复杂

class ShippingCostCalculator {
private static final double STANDARD_RATE_1 = 35.0;
private static final double STANDARD_RATE_2 = 30.0;
private static final double STANDARD_RATE_3 = 25.0;
private static final double STANDARD_RATE_4 = 15.0;

private static double calculateStandardRate(double mass) {
    if (mass < 20) return STANDARD_RATE_1;
    if (mass < 50) return STANDARD_RATE_2;
    if (mass < 100) return STANDARD_RATE_3;
    return STANDARD_RATE_4;
}

private static double calculateHazardousRate(double mass) {
    if (mass < 20) return 80.0;
    if (mass < 50) return 50.0;
    if (mass < 100) return 30.0;
    return 20.0;
}

private static double calculateExpressRate(double mass) {
    if (mass < 20) return 60.0;
    if (mass < 50) return 50.0;
    if (mass < 100) return 40.0;
    return 30.0;
}

public static double determineRateBasedOnCategory(String category, double mass) {
    switch (category) {
        case "Normal": return calculateStandardRate(mass);
        case "Dangerous": return calculateHazardousRate(mass);
        case "Expedite": return calculateExpressRate(mass);
        default: return 0;
    }
}

public static double computeSingleItemShippingFee(String category, double billingMass) {
    double rate = determineRateBasedOnCategory(category, billingMass);
    return Math.round(billingMass * rate * 10.0) / 10.0;
}

}
4.FlightDetails
这个是迭代后的结果,需要修改一些细节

class FlightDetails {
private String flightIdentifier;
private String originAirport;
private String destinationAirport;
private String operationDate;
private double maximumCapacity;

public FlightDetails(String id, String departure, String arrival,
                     String date, double capacity) {
    flightIdentifier = id;
    originAirport = departure;
    destinationAirport = arrival;
    operationDate = date;
    maximumCapacity = capacity;
}

public boolean verifyCapacity(double totalMass) {
    return totalMass <= maximumCapacity;
}

public String getFlightIdentifier() { return flightIdentifier; }

}
总体来说不难,而且构造函数可以用idea自带的生成来做,效率能提高很多

5.最最最麻烦的ShippingOrder函数

class ShippingOrder {
private String orderIdentifier;
private String creationDate;
private String senderLocation;
private String senderName;
private String senderContact;
private String receiverLocation;
private String receiverName;
private String receiverContact;
private String paymentType;
private ClientInfo client;
private List itemsList;
private FlightDetails flightInfo;

public ShippingOrder(String orderId, String date, String sendAddr, String sendName,
                     String sendPhone, String receiveAddr, String receiveName,
                     String receivePhone, ClientInfo clientInfo, List<ShipmentItem> items,
                     FlightDetails flight, String payment) {
    orderIdentifier = orderId;
    creationDate = date;
    senderLocation = sendAddr;
    senderName = sendName;
    senderContact = sendPhone;
    receiverLocation = receiveAddr;
    receiverName = receiveName;
    receiverContact = receivePhone;
    client = clientInfo;
    itemsList = items;
    flightInfo = flight;
    paymentType = payment;
}

public double computeTotalBillingMass() {
    return Math.round(itemsList.stream()
            .mapToDouble(ShipmentItem::determineBillingMass)
            .sum() * 10) / 10.0;
}

public String prepareOrderSummary() {
    double totalMass = computeTotalBillingMass();
    if (!flightInfo.verifyCapacity(totalMass)) {
        return String.format("The flight with flight number:%s has exceeded its load capacity and cannot carry the order.",
                flightInfo.getFlightIdentifier());
    }

    double baseCost = itemsList.stream()
            .mapToDouble(item -> ShippingCostCalculator.computeSingleItemShippingFee(
                    item.getItemCategory(), item.determineBillingMass()))
            .sum();

    double discountRate = client.getClientCategory().equals("Individual") ? 0.9 : 0.8;
    double finalCost = Math.round(baseCost * discountRate * 10) / 10.0;

    String paymentMethod = convertPaymentType(paymentType);

    StringBuilder summary = new StringBuilder();
    summary.append(String.format("客户:%s(%s)订单信息如下:\n",
                    client.getFullName(), client.getContactNumber()))
            .append("-----------------------------------------\n")
            .append(String.format("航班号:%s\n", flightInfo.getFlightIdentifier()))
            .append(String.format("订单号:%s\n", orderIdentifier))
            .append(String.format("订单日期:%s\n", creationDate))
            .append(createContactDetailsSection())
            .append(String.format("订单总重量(kg):%.1f\n", totalMass))
            .append(String.format("%s支付金额:%.1f\n\n", paymentMethod, finalCost))
            .append(prepareItemizedList());

    return summary.toString();
}

private String createContactDetailsSection() {
    return String.format("发件人姓名:%s\n发件人电话:%s\n发件人地址:%s\n" +
                    "收件人姓名:%s\n收件人电话:%s\n收件人地址:%s\n",
            senderName, senderContact, senderLocation,
            receiverName, receiverContact, receiverLocation);
}

private String prepareItemizedList() {
    StringBuilder itemList = new StringBuilder();
    itemList.append("货物明细如下:\n-----------------------------------------\n")
            .append("明细编号	货物名称	计费重量	计费费率	应交运费\n");

    int counter = 1;
    for (ShipmentItem item : itemsList) {
        double mass = item.determineBillingMass();
        double rate = ShippingCostCalculator.determineRateBasedOnCategory(
                item.getItemCategory(), mass);
        double fee = ShippingCostCalculator.computeSingleItemShippingFee(
                item.getItemCategory(), mass);

        itemList.append(String.format("%d	%s	%.1f	%.1f	%.1f\n",
                counter++, item.getProductName(), mass, rate, fee));
    }
    return itemList.toString();
}

private String convertPaymentType(String typeCode) {
    return switch (typeCode) {
        case "Wechat" -> "微信";
        case "ALiPay" -> "支付宝";
        case "Cash" -> "现金";
        default -> typeCode;
    };
}

}
这个函数是主要面向输出的,能让代码中的内容转换成对应的文字,所以又麻烦又关键,如果没写好就会报错,报一堆格式错误,非0返回之类的,而且很难找出问题,所以写的时候要仔细,不然用ai都不一定能找出错误,还会让自己变得更加迷糊
三、代码实现阶段 测试阶段

  1. 订单汇总生成器prepareOrderSummary()
    字符串拼接时遇到好多中文乱码问题,最后发现是输出格式不对

  2. 货物明细打印prepareItemizedList()
    刚开始没有给counter++,
    int counter = 1;
    for (ShipmentItem item : itemsList) {
    double mass = item.determineBillingMass();
    double rate = ShippingCostCalculator.determineRateBasedOnCategory(
    item.getItemCategory(), mass);
    double fee = ShippingCostCalculator.computeSingleItemShippingFee(
    item.getItemCategory(), mass);

         itemList.append(String.format("%d	%s	%.1f	%.1f	%.1f\n",
                 counter++, item.getProductName(), mass, rate, fee));
     }
     return itemList.toString();
    

然后打印出来一堆乱码,后面查了一下好像是循环体内变量作用域引发。

四、最后总结
在航空货运系统开发中,实际案例展现了代码与业务逻辑的深度绑定。ClientInfo类的构造函数曾因参数赋值错误导致数据混乱:误将contactNumber = id写入,测试时发现联系方式与客户ID相同,修正为contactNumber = phone后才解决。ShipmentItem的体积重量计算因整数除法出现重大偏差,原代码(30 * 40 * 50)/6000得到1kg的错误结果,改为6000.0后计算才正确。ShippingCostCalculator的三个费率策略采用独立方法实现,例如危险品在20kg以下收取80元/kg,与普通货物35元/kg形成明确区分。ShippingOrder的订单汇总曾因字符串拼接导致中文乱码,通过规范String.format编码解决;货物明细表的计数器初始版本忘记递增,导致所有条目编号为1,加入counter++后修复。这些具体问题表明,业务规则转化到代码时需要精确到变量级别的验证,例如支付方式中convertPaymentType将"Wechat"映射为"微信"的硬编码转换,直接影响了最终输出准确性。
这个项目带给我的不仅是Java语法熟练度的提升,更培养了系统工程师的全局视角。它教会我:优秀的软件开发者应该既能在抽象层面搭建稳固的框架;又能细心地发现每个可能引发故障的代码螺丝松动。这种在宏观与微观间自如切换的能力,将成为我职业航程中最宝贵的导航仪。正如波音747的诞生改变了航空史,每个精妙设计的系统都在重新定义数字世界的可能性边界。

posted @ 2025-05-21 21:58  24201326_邱经雨  阅读(30)  评论(0)    收藏  举报