南昌航空大学-软件学院-24201625-梁少康-第二次blog作业
1.前言
在经历第一次迭代作业以后,便紧接着迎来了第二次博客作业。很明显,第二次迭代作业主要考察代码的顶层设计,对程序的可扩展性要求提高;
1.关于题量
相较于第一次迭代作业来说,这一次的题量明显减少很多,迭代次数也从三次变为二次;
2.关于知识点
在知识点上这两次题目集在帮助我们熟悉java的基础语法和熟悉JAVA的几个设计原则,巩固和加深语法的使用规范。与前一次迭代作业不同的是,题目不再提供相应的类图,想要进行代码的实现,就必须进行对对象设计的基本过程,不断修复与完善;
3.关于难度
在算法方面这次迭代作业并无任何难度,都是基础的逻辑,主要是类之间的关系设计,所以相对比较简单,如果没有很好的代码设计的话,想进行代码实现还是有一点困难的,并且工作量会大大增加;
2.设计与分析
2.1 OPP-1 航空货运管理系统1
2.1.1 题目
7-3 NCHU_航空货运管理系统(类设计)
分数 60
中等
作者 段喜龙
单位 南昌航空大学
航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明参看说明文件。
输入格式:
按如下顺序分别输入客户信息、货物信息、航班信息以及订单信息。
客户编号
客户姓名
客户电话
客户地址
运送货物数量
货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
航班号
航班起飞机场
航班降落机场
航班日期(格式为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
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
栈限制
8192 KB
2.1.2 源码
import java.util.*;
class Information{
String address;
String name;
String number;
public Information(){}
public Information(String address, String name, String number){
this.address = address;
this.name = name;
this.number = number;
}
public String getAddress(){
return address;
}
public void setAddress(String address){
this.address = address;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String getNumber(){
return number;
}
}
class Customer_Information extends Information{
private String customerNumber;
public Customer_Information(){}
public Customer_Information(String address, String name, String number,String customerNumber){
super(address,name,number);
this.customerNumber = customerNumber;
}
public String getCustomerNumber(){
return customerNumber;
}
public void setCustomerNumber(String customerNumber){
this.customerNumber = customerNumber;
}
}
class Flight{
private String startAddress;
private String endAddress;
private String flightTime;
private int maxWeight;
private String FlightNumber;
public Flight(){}
public Flight(String startAddress, String endAddress, String flightTime, int maxWeight,String FlightNumber){
this.startAddress = startAddress;
this.endAddress = endAddress;
this.flightTime = flightTime;
this.maxWeight = maxWeight;
this.FlightNumber = FlightNumber;
}
public String getFlightNumber() {
return FlightNumber;
}
public void setFlightNumber(String flightNumber) {
FlightNumber = flightNumber;
}
public String getStartAddress(){
return startAddress;
}
public void setStartAddress(String startAddress){
this.startAddress = startAddress;
}
public String getEndAddress(){
return endAddress;
}
public void setEndAddress(String endAddress){
this.endAddress = endAddress;
}
public String getFlightTime(){
return flightTime;
}
public void setFlightTime(String flightTime){
this.flightTime = flightTime;
}
public double getMaxWeight(){
return maxWeight;
}
public void setMaxWeight(int maxWeight){
this.maxWeight = maxWeight;
}
}
class Goods{
private int number;
private String goodsName;
private int width;
private int length;
private int height;
private double weight;
private double grossWeight;
public Goods(int number, String goodsName, int width, int length, int height, double weight){
this.number = number;
this.goodsName = goodsName;
this.width = width;
this.length = length;
this.height = height;
this.weight = weight;
setGrossWeight();
}
public int getNumber(){
return number;
}
public void setNumber(int number){
this.number = number;
}
public String getGoodsName(){
return goodsName;
}
public void setGoodsName(String goodsName){
this.goodsName = goodsName;
}
public int getWidth(){
return width;
}
public void setWidth(int width){
this.width = width;
}
public int getLength(){
return length;
}
public void setLength(int length){
this.length = length;
}
public int getHeight(){
return height;
}
public void setHeight(int height){
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double getVolumeWeight(){
return (length * width * height)*1.0/6000;
}
public double getGrossWeight() {
return grossWeight;
}
public void setGrossWeight(){
this.grossWeight=Math.max(weight, getVolumeWeight());
}
public double getRate(){
double chargeWeight = getGrossWeight();
if (chargeWeight < 20) {
return 35;
} else if (chargeWeight < 50) {
return 30;
} else if (chargeWeight < 100) {
return 25;
} else {
return 15;
}
}
public double getCost() {
return getGrossWeight() * getRate();
}
}
class Agent{
private List<Goods> goodsList;
public Agent() {
this.goodsList = new ArrayList<>();
}
public void addGoods(Goods goods) {
this.goodsList.add(goods);
}
public List<Goods> getGoodsList() {
return goodsList;
}
public double getTotalWeight() {
double total = 0;
for (Goods goods : goodsList) {
total += goods.getGrossWeight();
}
return total;
}
public double getTotalCost() {
double total = 0;
for (Goods goods : goodsList) {
total += goods.getCost();
}
return total;
}
}
class Order {
private String orderId;
private String orderDate;
private Information sender;
private Information receiver;
private Flight flight;
private Agent agent;
public Order(String orderId, String orderDate, Information sender, Information receiver, Flight flight, Agent agent) {
this.orderId = orderId;
this.orderDate = orderDate;
this.sender = sender;
this.receiver = receiver;
this.flight = flight;
this.agent = agent;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getOrderDate() {
return orderDate;
}
public void setOrderDate(String orderDate) {
this.orderDate = orderDate;
}
public Information getSender() {
return sender;
}
public void setSender(Information sender) {
this.sender = sender;
}
public Information getReceiver() {
return receiver;
}
public void setReceiver(Information receiver) {
this.receiver = receiver;
}
public Flight getFlight() {
return flight;
}
public void setFlight(Flight flight) {
this.flight = flight;
}
public Agent getAgent() {
return agent;
}
public void setAgent(Agent agent) {
this.agent = agent;
}
public boolean canCarry() {
return agent.getTotalWeight() <= flight.getMaxWeight();
}
public void printOrderInfo(Customer_Information customer) {
System.out.printf("客户:%s(%s)订单信息如下:\n", customer.getName(), customer.getNumber());
System.out.println("-----------------------------------------");
System.out.printf("航班号:%s\n", flight.getFlightNumber());
System.out.printf("订单号:%s\n", orderId);
System.out.printf("订单日期:%s\n", orderDate);
System.out.printf("发件人姓名:%s\n", sender.getName());
System.out.printf("发件人电话:%s\n", sender.getNumber());
System.out.printf("发件人地址:%s\n", sender.getAddress());
System.out.printf("收件人姓名:%s\n", receiver.getName());
System.out.printf("收件人电话:%s\n", receiver.getNumber());
System.out.printf("收件人地址:%s\n", receiver.getAddress());
System.out.printf("订单总重量(kg):%.1f\n", agent.getTotalWeight());
System.out.printf("微信支付金额:%.1f\n", agent.getTotalCost());
System.out.println();
System.out.println("货物明细如下:");
System.out.println("-----------------------------------------");
System.out.println("明细编号\t货物名称\t计费重量\t计费费率\t应交运费");
int index = 1;
for (Goods goods : agent.getGoodsList()) {
System.out.printf("%d\t%s\t%.1f\t%.1f\t%.1f\n", index++, goods.getGoodsName(), goods.getGrossWeight(), goods.getRate(), goods.getCost());
}
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取客户信息
String customerNumber = scanner.nextLine();
String customerName = scanner.nextLine();
String customerPhone = scanner.nextLine();
String customerAddress = scanner.nextLine();
Customer_Information customer = new Customer_Information(customerAddress, customerName, customerPhone, customerNumber);
// 读取货物信息
int numGoods = scanner.nextInt();
scanner.nextLine(); // 消耗换行符
Agent agent = new Agent();
for (int i = 0; i < numGoods; i++) {
int goodsNumber = scanner.nextInt();
scanner.nextLine(); // 消耗换行符
String goodsName = scanner.nextLine();
int width = scanner.nextInt();
int length = scanner.nextInt();
int height = scanner.nextInt();
int weight = scanner.nextInt();
scanner.nextLine(); // 消耗换行符
Goods goods = new Goods(goodsNumber, goodsName, width, length, height, weight);
agent.addGoods(goods);
}
// 读取航班信息
String flightNumber = scanner.nextLine();
String startAddress = scanner.nextLine();
String endAddress = scanner.nextLine();
String flightDate = scanner.nextLine();
int maxWeight = scanner.nextInt();
scanner.nextLine(); // 消耗换行符
Flight flight = new Flight(startAddress, endAddress, flightDate, maxWeight,flightNumber);
// 读取订单信息
String orderId = scanner.nextLine();
String orderDate = scanner.nextLine();
String senderAddress = scanner.nextLine();
String senderName = scanner.nextLine();
String senderPhone = scanner.nextLine();
String receiverAddress = scanner.nextLine();
String receiverName = scanner.nextLine();
String receiverPhone = scanner.nextLine();
Information sender = new Information(senderAddress, senderName, senderPhone);
Information receiver = new Information(receiverAddress, receiverName, receiverPhone);
Order order = new Order(orderId, orderDate, sender, receiver, flight, agent);
if (!order.canCarry()) {
System.out.printf("The flight with flight number:%s has exceeded its load capacity and cannot carry the order.\n", flight.getFlightNumber());
} else {
order.printOrderInfo(customer);
}
scanner.close();
}
}
2.1.3 设计与分析


设计总结
一、系统设计概述
- 系统功能模块
基础信息模块:
Information 类:封装地址、姓名、电话等通用信息。
Customer_Information 类:继承 Information,新增客户编号,用于客户信息管理。
运输资源模块:
Flight 类:管理航班信息(起降地址、时间、载重、航班号)。
货物处理模块:
Goods 类:计算货物的体积重量、毛重(实际重量与体积重量取最大值)、运费费率及费用。
业务逻辑模块:
Agent 类:管理货物列表,计算总重量和总费用。
Order 类:整合订单全流程信息(客户、收发件人、航班、货物代理),校验载重并生成订单详情。 - 核心业务流程
输入数据:
读取客户信息 → 读取货物信息(支持多件货物)→ 读取航班信息 → 读取订单基础信息。
业务处理:
Goods 自动计算计费重量(毛重)和运费。
Agent 汇总货物总重量和总费用。
Order 校验航班载重是否超限,生成订单详情。
输出结果:
若载重超限,提示错误;否则打印详细的订单信息(含客户、航班、收发件人、货物明细)。
设计优点
- 面向对象设计规范
类职责清晰:
每个类专注于单一职责(如 Goods 只处理货物计算,Order 只处理订单逻辑),符合 单一职责原则。
继承关系合理:Customer_Information 继承 Information,复用通用字段,符合 开闭原则。
封装性良好:
成员变量私有化,通过公共方法(getter/setter)访问,保证数据安全性。 - 业务逻辑完整性
运费计算逻辑严谨:
体积重量计算公式(长 × 宽 × 高 / 6000)符合航空货运行业标准。
费率分级(<20kg、20-50kg、50-100kg、≥100kg)覆盖常见重量区间,计算逻辑清晰。
载重校验机制:
Order.canCarry() 方法确保订单总重量不超过航班最大载重,避免超载风险。 - 代码可读性与结构
注释与命名规范:
类名、方法名直观(如 getGrossWeight、printOrderInfo),便于理解功能。
输入输出逻辑通过注释分隔,代码结构层次分明。
模块化输入处理:
使用 Scanner 按模块顺序读取数据,流程清晰,易于调试。1. 面向对象设计规范
类职责清晰:
每个类专注于单一职责(如 Goods 只处理货物计算,Order 只处理订单逻辑),符合 单一职责原则。
继承关系合理:Customer_Information 继承 Information,复用通用字段,符合 开闭原则。
封装性良好:
成员变量私有化,通过公共方法(getter/setter)访问,保证数据安全性。 - 业务逻辑完整性
运费计算逻辑严谨:
体积重量计算公式(长 × 宽 × 高 / 6000)符合航空货运行业标准。
费率分级(<20kg、20-50kg、50-100kg、≥100kg)覆盖常见重量区间,计算逻辑清晰。
载重校验机制:
Order.canCarry() 方法确保订单总重量不超过航班最大载重,避免超载风险。 - 代码可读性与结构
注释与命名规范:
类名、方法名直观(如 getGrossWeight、printOrderInfo),便于理解功能。
输入输出逻辑通过注释分隔,代码结构层次分明。
模块化输入处理:
使用 Scanner 按模块顺序读取数据,流程清晰,易于调试。
2.1.4 踩坑心得
1.在开始代码设计之前一定要确认好类与类之间的关系,做好类的设计,不然在后续增改内容时很容易大面积修改代码,或者增添代码。这样不仅增添了自己的工作量,还会使代码的质量下降;
2.注意中间控制类的使用,合理的使用控制类会是你写代码更加得心应手;
3.在进行代码实现前一定要好好看清题目要求与程序逻辑,不然一个数据算错的话很难找到错误点在哪里。
2.1.5 改进建议
- 代码健壮性不足
问题:
未处理输入数据的合法性(如空字符串、负数重量 / 尺寸、非数字输入等),可能导致程序崩溃或逻辑错误。
Goods 构造方法中 weight 为 int 类型,但实际业务中可能需要支持小数(如 double)。
改进建议:
添加输入校验逻辑(如 goodsName 非空、尺寸 / 重量≥0),使用异常处理(try-catch)捕获非法输入。
将 Goods 的 weight 改为 double 类型,匹配实际业务场景。 - 扩展性有限
问题:
费率规则硬编码在 Goods.getRate() 中,若未来费率调整需修改代码,不符合 开闭原则。
缺少抽象类或接口(如 Transportable 接口),难以扩展其他运输方式(如海运、陆运)。
改进建议:
将费率规则抽象为配置文件(如 rates.properties)或枚举类,便于动态调整。
定义 Transport 抽象类,将 Flight 作为其子类,为后续扩展运输方式预留接口。 - 代码冗余与优化空间
问题:
Information 类的 number 字段命名不明确(“电话” 更合适),易引发歧义。
Order.printOrderInfo 方法中重复调用 agent.getTotalWeight() 和 goods.getGrossWeight(),可提前缓存结果。
改进建议:
将 Information.number 重命名为 phone,提高语义清晰度。
在 Agent 类中添加 totalWeight 和 totalCost 缓存字段,避免重复计算(需注意数据一致性)。
2.2 OPP-2: 航空货运管理系统2
2.2.1 题目
航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明参看说明文件。
OO第十二周作业题目说明.pdf
输入格式:
按如下顺序分别输入客户信息、货物信息、航班信息以及订单信息。
客户类型[可输入项:Individual/Corporate]
客户编号
客户姓名
客户电话
客户地址
货物类型[可输入项:Normal/Expedite/Dangerous]
运送货物数量
[货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为YYYY-MM-DD)
航班最大载重量
订单编号
订单日期(格式为YYYY-MM-DD)
发件人地址
发件人姓名
发件人电话
收件人地址
收件人姓名
收件人电话
支付方式[可输入项:Wechat/ALiPay/Cash]
输出格式:
如果订单中货物重量超过航班剩余载重量,程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order. ,程序终止运行。
如果航班载重量可以承接该订单,输出如下:
客户:姓名(电话)订单信息如下:
航班号:
订单号:
订单日期:
发件人姓名:
发件人电话:
发件人地址:
收件人姓名:
收件人电话:
收件人地址:
订单总重量(kg):
[微信/支付宝/现金]支付金额:
货物明细如下:
明细编号 货物名称 计费重量 计费费率 应交运费
1 ...
2 ...
注:输出中实型数均保留1位小数。
输入样例1:
在这里给出一组输入。例如:
Corporate
10001
郭靖
13807911234
南昌航空大学
Expedite
2
101
发电机
80
60
40
80
102
信号发生器
55
70
60
45
MU1234
昌北国际机场
大兴国际机场
2025-04-22
1000
900001
2025-04-22
南昌大学
洪七公
18907912325
北京大学
黄药师
13607912546
ALiPay
输出样例1:
在这里给出相应的输出。例如:
客户:郭靖(13807911234)订单信息如下:
-----------------------------------------
航班号:MU1234
订单号:900001
订单日期:2025-04-22
发件人姓名:洪七公
发件人电话:18907912325
发件人地址:南昌大学
收件人姓名:黄药师
收件人电话:13607912546
收件人地址:北京大学
订单总重量(kg):125.0
支付宝支付金额:4360.0
货物明细如下:
-----------------------------------------
明细编号 货物名称 计费重量 计费费率 应交运费
1 发电机 80.0 40.0 3200.0
2 信号发生器 45.0 50.0 2250.0
代码长度限制
24 KB
时间限制
400 ms
内存限制
64 MB
栈限制
8192 KB
2.2.2 源码
import java.util.*;
class Information{
String address;
String name;
String number;
public Information(){}
public Information(String address, String name, String number){
this.address = address;
this.name = name;
this.number = number;
}
public String getAddress(){
return address;
}
public void setAddress(String address){
this.address = address;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String getNumber(){
return number;
}
}
abstract class Payment{
protected Agent agent;
protected Payment(){};
public Payment(Agent agent){
this.agent = agent;
}
abstract void pay();
}
class Wechat extends Payment{
protected Wechat(){};
public Wechat(Agent agent){
super(agent);
}
public void pay(){
System.out.printf("微信支付金额:%.1f\n",agent.getTotalCost());
}
}
class AliPay extends Payment{
public AliPay(){};
public AliPay(Agent agent){
super(agent);
}
public void pay(){
System.out.printf("支付宝支付金额:%.1f\n",agent.getTotalCost());
}
}
class Cash extends Payment{
public Cash(){};
public Cash(Agent agent){
super(agent);
}
public void pay(){
System.out.printf("现金支付金额:%.1f\n",agent.getTotalCost());
}
}
class Customer_Information extends Information{
private String customerNumber;
private String customerType;
public Customer_Information(){}
public Customer_Information(String address, String name, String number,String customerNumber,String customerType){
super(address,name,number);
this.customerNumber = customerNumber;
this.customerType = customerType;
}
public String getCustomerNumber(){
return customerNumber;
}
public void setCustomerNumber(String customerNumber){
this.customerNumber = customerNumber;
}
public String getCustomerType(){
return customerType;
}
public void setCustomerType(String customerType){
this.customerType = customerType;
}
}
class Flight{
private String startAddress;
private String endAddress;
private String flightTime;
private int maxWeight;
private String FlightNumber;
public Flight(){}
public Flight(String startAddress, String endAddress, String flightTime, int maxWeight,String FlightNumber){
this.startAddress = startAddress;
this.endAddress = endAddress;
this.flightTime = flightTime;
this.maxWeight = maxWeight;
this.FlightNumber = FlightNumber;
}
public String getFlightNumber() {
return FlightNumber;
}
public void setFlightNumber(String flightNumber) {
FlightNumber = flightNumber;
}
public String getStartAddress(){
return startAddress;
}
public void setStartAddress(String startAddress){
this.startAddress = startAddress;
}
public String getEndAddress(){
return endAddress;
}
public void setEndAddress(String endAddress){
this.endAddress = endAddress;
}
public String getFlightTime(){
return flightTime;
}
public void setFlightTime(String flightTime){
this.flightTime = flightTime;
}
public double getMaxWeight(){
return maxWeight;
}
public void setMaxWeight(int maxWeight){
this.maxWeight = maxWeight;
}
}
class Goods{
private int number;
private String goodsName;
private int width;
private int length;
private int height;
private double weight;
private double grossWeight;
private String goodsType;
public Goods(int number, String goodsName, int width, int length, int height, double weight,String goodsType){
this.number = number;
this.goodsName = goodsName;
this.width = width;
this.length = length;
this.height = height;
this.weight = weight;
this.goodsType = goodsType;
setGrossWeight();
}
public int getNumber(){
return number;
}
public void setNumber(int number){
this.number = number;
}
public String getGoodsName(){
return goodsName;
}
public void setGoodsName(String goodsName){
this.goodsName = goodsName;
}
public int getWidth(){
return width;
}
public void setWidth(int width){
this.width = width;
}
public int getLength(){
return length;
}
public void setLength(int length){
this.length = length;
}
public int getHeight(){
return height;
}
public void setHeight(int height){
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double getVolumeWeight(){
return (length * width * height)*1.0/6000;
}
public double getGrossWeight() {
return grossWeight;
}
public void setGrossWeight(){
this.grossWeight=Math.max(weight, getVolumeWeight());
}
public String getGoodsType(){
return goodsType;
}
public void setGoodsType(String goodsType){
this.goodsType = goodsType;
}
public double getRate() {
double chargeWeight = getGrossWeight();
switch (goodsType) {
case "Normal":
if (chargeWeight < 20) return 35;
else if (chargeWeight < 50) return 30;
else if (chargeWeight < 100) return 25;
else return 15;
case "Expedite":
if (chargeWeight < 20) return 60;
else if (chargeWeight < 50) return 50;
else if (chargeWeight < 100) return 40;
else return 30;
case "Dangerous":
if (chargeWeight < 20) return 80;
else if (chargeWeight < 50) return 50;
else if (chargeWeight < 100) return 30;
else return 20;
default:
return 0;
}
}
public double getCost() {
return getGrossWeight() * getRate();
}
}
class Agent{
private List<Goods> goodsList;
private Customer_Information customerInformation;
public Agent(Customer_Information customerInformation) {
this.goodsList = new ArrayList<>();
this.customerInformation = customerInformation;
}
public void addGoods(Goods goods) {
this.goodsList.add(goods);
}
public List<Goods> getGoodsList() {
return goodsList;
}
public double getTotalWeight() {
double total = 0;
for (Goods goods : goodsList) {
total += goods.getGrossWeight();
}
return total;
}
public double getTotalCost() {
double total = 0;
for (Goods goods : goodsList) {
total += goods.getCost();
}
if(customerInformation.getCustomerType().equals("Individual"))
return total*0.9;
else
return total*0.8;
}
}
class Order {
private String orderId;
private String orderDate;
private Information sender;
private Information receiver;
private Flight flight;
private Agent agent;
private Payment pay;
public Order(String orderId, String orderDate, Information sender, Information receiver, Flight flight, Agent agent, Payment pay) {
this.orderId = orderId;
this.orderDate = orderDate;
this.sender = sender;
this.receiver = receiver;
this.flight = flight;
this.agent = agent;
this.pay = pay;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getOrderDate() {
return orderDate;
}
public void setOrderDate(String orderDate) {
this.orderDate = orderDate;
}
public Information getSender() {
return sender;
}
public void setSender(Information sender) {
this.sender = sender;
}
public Information getReceiver() {
return receiver;
}
public void setReceiver(Information receiver) {
this.receiver = receiver;
}
public Flight getFlight() {
return flight;
}
public void setFlight(Flight flight) {
this.flight = flight;
}
public Agent getAgent() {
return agent;
}
public void setAgent(Agent agent) {
this.agent = agent;
}
public boolean canCarry() {
return agent.getTotalWeight() <= flight.getMaxWeight();
}
public void printOrderInfo(Customer_Information customer) {
System.out.printf("客户:%s(%s)订单信息如下:\n", customer.getName(), customer.getNumber());
System.out.println("-----------------------------------------");
System.out.printf("航班号:%s\n", flight.getFlightNumber());
System.out.printf("订单号:%s\n", orderId);
System.out.printf("订单日期:%s\n", orderDate);
System.out.printf("发件人姓名:%s\n", sender.getName());
System.out.printf("发件人电话:%s\n", sender.getNumber());
System.out.printf("发件人地址:%s\n", sender.getAddress());
System.out.printf("收件人姓名:%s\n", receiver.getName());
System.out.printf("收件人电话:%s\n", receiver.getNumber());
System.out.printf("收件人地址:%s\n", receiver.getAddress());
System.out.printf("订单总重量(kg):%.1f\n", agent.getTotalWeight());
pay.pay();
System.out.println();
System.out.println("货物明细如下:");
System.out.println("-----------------------------------------");
System.out.println("明细编号\t货物名称\t计费重量\t计费费率\t应交运费");
int index = 1;
for (Goods goods : agent.getGoodsList()) {
System.out.printf("%d\t%s\t%.1f\t%.1f\t%.1f\n", index++, goods.getGoodsName(), goods.getGrossWeight(), goods.getRate(), goods.getCost());
}
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取客户信息
String customerType = scanner.nextLine();
String customerNumber = scanner.nextLine();
String customerName = scanner.nextLine();
String customerPhone = scanner.nextLine();
String customerAddress = scanner.nextLine();
Customer_Information customer = new Customer_Information(customerAddress, customerName, customerPhone, customerNumber,customerType);
// 读取货物信息
String goodsType = scanner.nextLine();
int numGoods = scanner.nextInt();
Agent agent = new Agent(customer);
for (int i = 0; i < numGoods; i++) {
int goodsNumber = scanner.nextInt();
scanner.nextLine(); // 消耗换行符
String goodsName = scanner.nextLine();
int width = scanner.nextInt();
int length = scanner.nextInt();
int height = scanner.nextInt();
int weight = scanner.nextInt();
Goods goods = new Goods(goodsNumber, goodsName, width, length, height, weight,goodsType);
agent.addGoods(goods);
}
// 读取航班信息
scanner.nextLine();
String flightNumber = scanner.nextLine();
String startAddress = scanner.nextLine();
String endAddress = scanner.nextLine();
String flightDate = scanner.nextLine();
int maxWeight = scanner.nextInt();
scanner.nextLine(); // 消耗换行符
Flight flight = new Flight(startAddress, endAddress, flightDate, maxWeight,flightNumber);
// 读取订单信息
String orderId = scanner.nextLine();
String orderDate = scanner.nextLine();
String senderAddress = scanner.nextLine();
String senderName = scanner.nextLine();
String senderPhone = scanner.nextLine();
String receiverAddress = scanner.nextLine();
String receiverName = scanner.nextLine();
String receiverPhone = scanner.nextLine();
String paymentType = scanner.nextLine();
Information sender = new Information(senderAddress, senderName, senderPhone);
Information receiver = new Information(receiverAddress, receiverName, receiverPhone);
Payment payment;
if(paymentType.equals("Wechat")) {
payment=new Wechat(agent);
}else if(paymentType.equals("ALiPay")) {
payment=new AliPay(agent);
}else{
payment =new Cash(agent);
}
Order order = new Order(orderId, orderDate, sender, receiver, flight, agent, payment);
if (!order.canCarry()) {
System.out.printf("The flight with flight number:%s has exceeded its load capacity and cannot carry the order.\n", flight.getFlightNumber());
} else {
order.printOrderInfo(customer);
}
scanner.close();
}
}
2.2.3 设计与分析


设计与分析总结
一.系统设计升级亮点
- 新增支付模块:策略模式的应用
设计架构:
定义抽象类 Payment,声明 pay() 抽象方法,通过 Wechat、AliPay、Cash 实现具体支付逻辑,符合 策略模式(行为封装与动态切换)。
Order 类持有 Payment 实例,通过构造方法注入具体支付方式,实现支付方式与订单逻辑的解耦。
优势:
新增支付方式时只需创建新子类(如 UnionPay),无需修改原有代码,完全遵循 开闭原则。
支付逻辑从 Order.printOrderInfo 中剥离,避免业务逻辑冗余,提升代码可维护性。 - 客户类型与货物类型的差异化处理
客户类型折扣:
Customer_Information 新增 customerType 字段(Individual/Company),Agent.getTotalCost() 根据客户类型应用不同折扣(个人 9 折,企业 8 折),体现业务场景中的客户分层策略。
货物类型费率:
Goods 新增 goodsType 字段(Normal/Expedite/Dangerous),getRate() 方法通过 switch-case 实现不同货物类型的费率规则,满足航空货运中危险品、加急件等特殊货物的定价需求。 - 类职责优化
Agent 类增强:
构造方法接收 Customer_Information 实例,将客户类型折扣逻辑封装在 Agent 中,避免 Order 类承担过多计算职责,符合 单一职责原则。
输入流程模块化:
按「客户信息 → 货物类型 → 货物详情 → 航班信息 → 订单信息 → 支付方式」顺序读取数据,逻辑分层清晰,便于调试和扩展。
二、核心设计模式与原则 - 继承与多态
Customer_Information 继承 Information,复用基础信息字段,新增客户专属属性(编号、类型),体现 IS-A 关系。
Payment 及其子类通过多态实现不同支付行为的统一调用(pay.pay()),运行时动态绑定具体实现,提升系统灵活性。 - 数据封装与接口隔离
所有类的成员变量均为私有,通过公共方法(getter/setter)访问,确保数据安全性。
Goods 将体积重量、毛重、费率等计算逻辑封装为内部方法,对外暴露简洁接口(如 getCost()),符合 接口隔离原则。 - 策略模式与模板方法
支付模块采用策略模式,将变化的支付行为抽象为策略族(Payment 子类),稳定的订单流程(Order)依赖抽象策略,降低耦合度。
Goods.getRate() 通过模板方法(固定流程:根据货物类型 → 重量区间 → 匹配费率)处理差异化业务规则,便于未来扩展新货物类型。
2.2.4 踩坑心得
1.注意具体看清题目,改动增加了很多内容,如货物类型,客户类型,支付方式等等,不然后面没看清又得重写;
2.类数量的增加一定要搞清楚类与类之间的关系,新增方法放在哪一个类上,注意思考如何设计才能使代码修改得更加合理,特别是其中Pay与其他类对应的关系,减少代码的重复;
3.一定注意一次性读入的时候在读取中就对输入数据进行过滤不合理数据,否则当你全部读取储存到数据再来剔除的话会增加代码的复杂度,增加不必要的代码实现。
2.2.5 改进建议
- 硬编码与配置化缺失
问题:
客户类型折扣比例(9 折 / 8 折)、货物类型枚举值(Normal/Expedite)、体积重量计算公式(除以 6000)均为硬编码,若业务规则变更需修改代码。
改进建议:
将折扣比例、费率规则、计算公式移至配置文件(如 config.properties)或枚举类:
java
public enum CustomerDiscount {
INDIVIDUAL(0.9), COMPANY(0.8);
private final double rate;
CustomerDiscount(double rate) { this.rate = rate; }
public double getRate() { return rate; }
}
使用 ResourceBundle 读取配置文件,实现动态参数管理。
2. 输入校验与异常处理不足
问题:
未校验 customerType 和 goodsType 的合法性(如输入非枚举值),可能导致 switch-case 进入 default 分支返回 0 费率,引发计算错误。
货物尺寸、重量可能为负数或零,未做合法性检查,违反业务逻辑(如体积重量计算公式要求长宽高 > 0)。
改进建议:
在 Customer_Information 和 Goods 的构造方法中添加参数校验:
java
// Goods 构造方法示例
public Goods(int number, String goodsName, int width, int length, int height, double weight, String goodsType) {
if (width <= 0 || length <= 0 || height <= 0 || weight < 0) {
throw new IllegalArgumentException("Invalid goods dimensions or weight");
}
// ... 其他逻辑
}
使用 Enum 定义合法的客户类型和货物类型,确保输入值有效:
java
public enum CustomerType { INDIVIDUAL, COMPANY }
public enum GoodsType { NORMAL, EXPEDITE, DANGEROUS }
- 代码冗余与性能优化
问题:
Agent.getTotalCost() 每次调用时遍历货物列表计算总费用,若多次调用(如订单打印、支付校验)会重复计算。
Order.printOrderInfo 中 agent.getTotalWeight() 被调用一次,goods.getGrossWeight() 在循环中多次调用,可缓存结果提升性能。
改进建议:
在 Agent 类中添加 totalWeight 和 totalCost 缓存字段,并在 addGoods 或计算方法中更新缓存:
java
private double cachedTotalWeight;
private double cachedTotalCost;
public void addGoods(Goods goods) {
goodsList.add(goods);
cachedTotalWeight += goods.getGrossWeight();
cachedTotalCost += goods.getCost();
}
public double getTotalWeight() {
return cachedTotalWeight;
}
在 Order.printOrderInfo 中提前缓存总重量:
java
double totalWeight = agent.getTotalWeight();
System.out.printf("订单总重量(kg):%.1f\n", totalWeight);
3.总结
作为 Java 面向对象思想的初始学习者,这两次代码作业让我逐步掌握了类与对象的设计及封装、继承、多态的应用。
首次作业中,我通过定义Information及其子类Customer_Information实现基础信息继承,用Goods类封装货物计算逻辑,初步理解单一职责原则。订单流程中通过Order整合各模块,体现对象协作。
第二次作业引入抽象类Payment及微信、支付宝等具体支付类,运用策略模式实现支付方式解耦,增强扩展性。同时,通过客户类型折扣、货物类型差异化费率,深化了多态与条件逻辑分离的设计思想。新增的Agent类缓存计算结果,优化了性能。
两次实践让我认识到面向对象设计需兼顾职责分离与灵活性,未来需加强输入校验、配置化设计及单元测试,提升代码健壮性。

浙公网安备 33010602011771号