航空货运管理系统(继承与多态)
航空货运管理系统开发日志
一、需求分析阶段:从一团糟倒层层剖析
最开始盯着五个类头皮发麻,仔细分析,然后画出对应的类图之后才稍微有点思路。特别纠结费率的实现方式,后来发现其实只需要设计一个专门计算的ShippingCostCalculator,然后定义好接口就能搞定。
这是刚开始画的类图
二、类设计阶段
- 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;
}
-
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后才恢复正常。
![]()
-
最烧脑的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
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都不一定能找出错误,还会让自己变得更加迷糊
三、代码实现阶段 测试阶段
-
订单汇总生成器prepareOrderSummary()
字符串拼接时遇到好多中文乱码问题,最后发现是输出格式不对 -
货物明细打印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的诞生改变了航空史,每个精妙设计的系统都在重新定义数字世界的可能性边界。




浙公网安备 33010602011771号