第二次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% 以上的运行时错误。记住:程序的健壮性不取决于 “正常情况”,而取决于 “异常情况” 的处理是否完善。
这些心得都是从一次次调试和重构中总结出来的,现在回头看,代码质量的提升本质上是 “用简单方式解决复杂问题” 的思维转变。未来再开发类似系统时,我会更注重从需求出发,用 “刚刚好” 的设计和技术,写出既灵活又易维护的代码。

浙公网安备 33010602011771号