第二次blog作业
一、前言
1.题目集总结
这次的两个题目集主要是考察我们的类设计、继承与多态已及接口,题目虽然说不难,但是仍然能够反映出我许许多多的问题。题目集9的最后一题是在题目集8的最后一题的基础上划分了多种客户类型和货物类型以及支付方式,增加了功能需求。根据不同的客户类型,选择不同的折扣方式,根据不同的货物类型选择不同的费率。
2.差异点
| 维度 | 第一题(2025.04) | 第二题(2025.05,新增 / 修改) |
|---|---|---|
| 费率规则 | 分段计算(重量区间对应不同费率) | 与货物类型绑定(普通 / 危险 / 加急货物) |
| 运费公式 | 基础运费 = 计费重量 × 费率 | 基础运费 = 计费重量 × 费率 × 折扣率(用户类型决定) |
| 用户类型 | 未提及 | 新增:个人用户(9 折)、集团用户(8 折) |
| 支付方式 | 支付宝、微信支付 | 新增:现金支付 |
| 设计原则考核 | 单一职责、里氏代换、开闭、合成复用(4 项) | 新增:依赖倒转原则(共 5 项) |
| 可扩展类提示 | 无 | 提示可扩展用户、支付方式、货物类 |
3.总结
- 第一题:侧重基础面向对象设计,通过分段费率考核单一职责与合成复用。
- 第二题:增加业务复杂度(货物类型、用户折扣、支付方式),强化设计原则的综合应用,尤其是开闭原则(新增类型不修改代码)和依赖倒转原则(抽象层解耦)。
- 核心目标:通过合理的类设计(继承、接口、组合),使系统易于扩展,同时满足各设计原则的单一职责划分。
二、设计与分析
1.题目集08“航天管理系统”
题目
点击查看题目
某航空公司“航空货运管理系统”中的空运费的计算涉及多个因素,通常包
括货物重量/体积、运输距离、附加费用、货物类型、客户类型以及市场供需等。
本次作业主要考虑货物重量/体积,以下是具体的计算方式和关键要点:
一、计费重量的确定
空运以实际重量(GrossWeight)和体积重量(VolumeWeight)中的较
高者作为计费重量。
计算公式:
体积重量(kg)= 货物体积(长×宽×高,单位:厘米)÷6000
示例:
若货物实际重量为80kg,体积为120cm×80cm×60cm,则:
体积重量 =(120×80×60)÷6000=96kg
计费重量取96kg(因96kg>80kg)。
二、基础运费计算
费率(Rate):航空公司或货代根据航线、货物类型、市场行情等制定(如
CNY 30/kg)。本次作业费率采用分段计算方式:
公式:基础运费 = 计费重量 × 费率
三、题目说明
本次题目模拟某客户到该航空公司办理一次货运业务的过程:
航空公司提供如下信息:
航班信息(航班号,航班起飞机场所在城市,航班降落机场所在城市,航班
日期,航班最大载重量)
客户填写货运订单并进行支付,需要提供如下信息:
客户信息(姓名,电话号码等)
货物信息(货物名称,货物包装长、宽、高尺寸,货物重量等)
运送信息(发件人姓名、电话、地址,收件人姓名、电话、地址,所选
航班号,订单日期)
支付方式(支付宝支付、微信支付)
注:一个货运订单可以运送多件货物,每件货物均需要根据重量及费率单独
计费。
程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信
息报表及货物明细报表。
四、题目要求
本次题目重点考核面向对象设计原则中的单一职责原则、里氏代换原则、开
闭原则以及合成复用原则,除需要在PTA平台提交源码外,还需要在超星平台
提交本次作业最终得分源码(首次提交最高分源码)的类图,评判标准为:
基础得分:PTA实际得分
设计因素:单一职责原则(40%)、里氏代换原则(20%)、开闭原则(20%)、
合成复用原则(20%)
分析
1.业务场景与功能要求
- 模拟货运订单流程:用户输入客户信息、货物信息、运送信息、支付方式等,生成订单报表和货物明细报表。
- 核心计算逻辑:
计费重量:取实际重量与体积重量的较大值(体积重量 = 长 × 宽 × 高 ÷6000)。
基础运费:分段费率计算(费率随重量区间变化,如重量 < 2kg、2kg≤重量 <?? 等,需注意题目中公式可能存在排版问题,需明确各重量区间的费率)。
多货物处理:一个订单包含多件货物,每件单独计费。
2.输入与输出要求
- 输入信息:
客户信息(姓名、电话)。
货物信息(名称、长、宽、高、实际重量)。
运送信息(发件人 / 收件人信息、航班号、订单日期)。
支付方式(支付宝、微信)。 - 输出报表:
订单信息报表(汇总订单基本信息)。
货物明细报表(每件货物的计费重量、运费等详情)。
代码展示与分析
点击查看代码
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner ac=new Scanner(System.in);
Sender sender=new Sender(ac.next(),ac.next(),ac.next(),ac.next());
int n= ac.nextInt();
ArrayList<Cargo> cargos=new ArrayList<>();
for(int i=0;i<n;i++){
Cargo cargo=new Cargo(ac.next(),ac.next(), ac.nextDouble(), ac.nextDouble(), ac.nextDouble(), ac.nextDouble());
cargos.add(cargo);
}
Flight flight=new Flight(ac.next(), ac.next(), ac.next(), ac.next(), ac.nextInt(), cargos);
String number=ac.next();
String data= ac.next();
String add1=ac.next();
Consignee consignee1=new fa(ac.next(), ac.next(), add1);
String add2=ac.next();
Consignee consignee2=new shou(ac.next(), ac.next(), add2);
Transport transport=new Transport(consignee1,consignee2,number,data);
Control control=new Control(flight,transport,sender);
if(flight.overload()){
System.out.printf("The flight with flight number:%s has exceeded its load capacity and cannot carry the order.",flight.getFlightNumber());
return;
}
control.print();
}
}
class Cargo {
private String number;
private String name;//名字
private double length;//长度
private double width;//宽度
private double height;//高度
private double weight;//重量
public Cargo() {
}
public Cargo(String number,String name, double length, double width, double height, double weight) {
this.number=number;
this.name = name;
this.length = length;
this.width = width;
this.height = height;
this.weight =Math.max(length*width*height/6000.0,weight);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double getMoney(){
return Math.max(length*width*height/6000.0,weight)*Sort.Rates(Math.max(length*width*height/6000.0,weight));
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
abstract class Consignee extends People{//收
public Consignee() {
}
public Consignee(String name, String number, String address){
super(name,number,address);
}
public abstract void show();
}
class Control {
private Flight flight;
private Transport transport;
private Sender sender;
public Control() {
}
public Control(Flight flight, Transport transport, Sender sender) {
this.flight = flight;
this.transport = transport;
this.sender = sender;
}
public void print(){
sender.show();
System.out.println("订单信息如下:");
System.out.println("-----------------------------------------");
System.out.println("航班号:"+flight.getFlightNumber());
transport.show();
System.out.printf("订单总重量(kg):%.1f\n",flight.allWeight());
System.out.printf("微信支付金额:%.1f\n\n",flight.allMoney());
System.out.println("货物明细如下:");
System.out.println("-----------------------------------------");
System.out.println("明细编号 货物名称 计费重量 计费费率 应交运费");
for (int i = 0; i < flight.getCargos().size(); i++) {
System.out.printf("%d %s %.1f %.1f %.1f\n",i+1,flight.getCargos().get(i).getName(),flight.getCargos().get(i).getWeight(),Sort.Rates(flight.getCargos().get(i).getWeight()),flight.getCargos().get(i).getMoney());
}
}
}
class fa extends Consignee{
public fa() {
}
public fa(String name, String number, String address) {
super(name, number, address);
}
@Override
public void show() {
System.out.println("发件人姓名:"+name);
System.out.println("发件人电话:"+number);
System.out.println("发件人地址:"+address);
}
}
class Flight {//航班信息
private String flightNumber;//航班号
private String upCity;//起飞城市
private String downCity;//降落城市
private String data;//航班日期
private int maxLoad;//航班最大载重
private ArrayList<Cargo> cargos=new ArrayList<>();
public Flight() {
}
public Flight(String flightNumber, String upCity, String downCity, String data, int maxLoad, ArrayList<Cargo> cargos) {
this.flightNumber = flightNumber;
this.upCity = upCity;
this.downCity = downCity;
this.data = data;
this.maxLoad = maxLoad;
this.cargos = cargos;
}
public String getFlightNumber() {
return flightNumber;
}
public void setFlightNumber(String flightNumber) {
this.flightNumber = flightNumber;
}
public String getUpCity() {
return upCity;
}
public void setUpCity(String upCity) {
this.upCity = upCity;
}
public String getDownCity() {
return downCity;
}
public void setDownCity(String downCity) {
this.downCity = downCity;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public int getMaxLoad() {
return maxLoad;
}
public void setMaxLoad(int maxLoad) {
this.maxLoad = maxLoad;
}
public ArrayList<Cargo> getCargos() {
return cargos;
}
public void setCargos(ArrayList<Cargo> cargos) {
this.cargos = cargos;
}
public boolean overload(){
return allWeight() > maxLoad;
}
public double allWeight(){
double allWeight=0.0;
for (Cargo cargo : cargos) {
allWeight += cargo.getWeight();
}
return allWeight;
}
public double allMoney(){
double allMoney=0.0;
for (Cargo cargo : cargos) {
allMoney += cargo.getMoney();
}
return allMoney;
}
}
abstract class People {
public String name;
public String number;
public String address;
public People() {
}
public People(String name, String number, String address) {
this.name = name;
this.number = number;
this.address = address;
}
public abstract void show();
}
class Sender extends People{//寄
String go;
public Sender() {
}
public Sender(String go,String name, String number, String address) {
super(name, number, address);
this.go=go;
}
@Override
public void show(){
System.out.print("客户:"+name+"("+number+")");
}
}
class shou extends Consignee{
public shou() {
}
public shou(String name, String number, String address) {
super(name, number, address);
}
@Override
public void show() {
System.out.println("收件人姓名:"+name);
System.out.println("收件人电话:"+number);
System.out.println("收件人地址:"+address);
}
}
class Sort {
private Sort(){
}
public static double Rates(double weight){
if(weight<20){
return 35;
} else if (weight>=20&&weight<50) {
return 30;
} else if (weight>=50&&weight<100) {
return 25;
}else {
return 15;
}
}
}
class Transport {//订单信息
private Consignee fa;
private Consignee shou;
private String number;
private String data;
public Transport(Consignee fa, Consignee consignee, String number, String data) {
this.fa = fa;
this.shou = consignee;
this.number = number;
this.data = data;
}
public Consignee getFa() {
return fa;
}
public void setFa(Consignee fa) {
this.fa = fa;
}
public Consignee getShou() {
return shou;
}
public void setShou(Consignee shou) {
this.shou = shou;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public void show(){
System.out.println("订单号:"+number);
System.out.println("订单日期:"+data);
fa.show();
shou.show();
}
}
类图

分析结果

点击查看分析结果
Metrics Details For File 'Main.java'
--------------------------------------------------------------------------------------------
Parameter Value
========= =====
Project Directory D:\java_code\pta\src\__5\
Project Name siyian
Checkpoint Name Baseline
File Name Main.java
Lines 371
Statements 106
Percent Branch Statements 2.8
Method Call Statements 48
Percent Lines with Comments 1.6
Classes and Interfaces 6
Methods per Class 4.33
Average Statements per Method 2.96
Line Number of Most Complex Method 7
Name of Most Complex Method Main.main()
Maximum Complexity 3
Line Number of Deepest Block 13
Maximum Block Depth 3
Average Block Depth 1.49
Average Complexity 1.12
--------------------------------------------------------------------------------------------
Most Complex Methods in 5 Class(es): Complexity, Statements, Max Depth, Calls
Cargo.Cargo() 1, 6, 2, 0
Cargo.Cargo() 1, 0, 0, 0
Cargo.getHeight() 1, 1, 2, 0
Cargo.getLength() 1, 1, 2, 0
Cargo.getMoney() 1, 1, 2, 3
Cargo.getName() 1, 1, 2, 0
Cargo.getNumber() 1, 1, 2, 0
Cargo.getWeight() 1, 1, 2, 0
Cargo.getWidth() 1, 1, 2, 0
Cargo.setHeight() 1, 1, 2, 0
Cargo.setLength() 1, 1, 2, 0
Cargo.setName() 1, 1, 2, 0
Cargo.setNumber() 1, 1, 2, 0
Cargo.setWeight() 1, 1, 2, 0
Cargo.setWidth() 1, 1, 2, 0
Control.Control() 1, 3, 2, 0
Control.Control() 1, 0, 0, 0
Control.print() 2, 6, 3, 7
fa.fa() 1, 1, 2, 1
fa.fa() 1, 0, 0, 0
fa.show() 1, 3, 2, 3
Main.main() 3, 20, 3, 26
shou.shou() 1, 1, 2, 1
shou.shou() 1, 0, 0, 0
shou.show() 1, 5, 2, 5
--------------------------------------------------------------------------------------------
Block Depth Statements
0 11
1 37
2 53
3 5
4 0
5 0
6 0
7 0
8 0
9+ 0
--------------------------------------------------------------------------------------------
一、整体概况
1. 代码规模
- 行数(Lines):371 行(含空行和注释),代码量适中,但需注意类和方法的组织是否清晰。
- 类与接口(Classes and Interfaces):6 个类,符合小型项目结构,但需检查职责是否单一。
- 方法数量:共 26 个方法,平均每个类约 4.33 个方法,方法数量分布较均匀。
2. 复杂度
- 最大复杂度(Maximum Complexity):3(位于 Main.main() 方法),整体复杂度较低,但主方法复杂度略高需关注。
- 平均复杂度(Average Complexity):1.12,大部分方法逻辑简单,符合设计原则。
- 块深度(Block Depth):最深块深度为 3(位于 Main.main() 和 Control.print()),嵌套层次较少,代码可读性较好。
二、关键问题分析
1. 类职责清晰度(单一职责原则)
- Cargo 类:
包含属性读写方法(如 getLength()、setWeight())和 getMoney() 计算方法,职责较单一,但需确认是否混合了数据存储与业务逻辑。 - 总结:若 getMoney() 仅涉及运费计算,可考虑将计算逻辑移至独立的 FreightCalculator 类,符合 合成复用原则。
- Control 类:
print() 方法复杂度为 2,块深度为 3,涉及报表输出逻辑。若该类同时处理业务控制和输出,可能职责混杂。 - 总结:拆分 Control 类为 BusinessController(业务逻辑)和 OutputController(输出逻辑),确保单一职责。
2.代码可读性与注释
- 注释比例:仅 1.6% 的行包含注释,关键逻辑(如费率分段计算、计费重量规则)缺乏注释,可能影响维护。
- 总结:
在 Cargo 类的 getChargeWeight() 方法中添加注释,说明 “取实际重量与体积重量的较大值” 逻辑。
在 Control.print() 或 Order.generateReport() 中注释报表字段含义(如 “计费重量 = 体积重量与实际重量取最大值”)。
三、设计原则合规性检查
-
- 合成复用原则(CRP)
当前实现:Cargo 类直接包含计算逻辑,未通过组合使用工具类(如 WeightCalculator)。
改进方向:将计费重量计算、运费计算封装为独立工具类,通过组合注入到 Cargo 或 Order 类中。
- 合成复用原则(CRP)
-
- 里氏代换原则(LSP)与开闭原则(OCP)
扩展性不足:若后续需新增货物类型或费率规则,当前设计可能需要修改 Cargo 类或主逻辑,违背开闭原则。
改进方向:
定义 CargoType 接口,普通货物、危险货物等实现接口,通过多态计算费率。
使用策略模式封装费率计算策略,允许新增策略而不修改原有代码。
- 里氏代换原则(LSP)与开闭原则(OCP)
四、总结
| 问题类型 | 具体建议 | 设计原则关联 |
|---|---|---|
| 类职责混杂 | 拆分 Control 类为业务控制和输出模块,Cargo 类剥离计算逻辑到工具类。 | 单一职责、合成复用原则 |
| 缺乏抽象与扩展 | 引入接口(如 CargoType、PaymentMethod)和策略模式,支持未来扩展。 | 里氏代换、开闭原则 |
| 代码可读性不足 | 添加关键逻辑注释,删除冗余构造方法,规范变量命名。 | 代码可维护性 |
当前代码结构基本符合小型项目要求,复杂度可控,但在 类职责划分 和 可扩展性设计 上存在提升空间。通过拆分主方法逻辑、引入抽象接口和策略模式,可进一步满足面向对象设计原则,提升系统的可维护性和应对需求变化的能力。要注意对关键业务逻辑添加注释。
2.题目集08“航天管理系统”
题目
点击查看题目
某航空公司“航空货运管理系统”中的空运费的计算涉及多个因素,通常包
括货物重量/体积、运输距离、附加费用、货物类型、客户类型以及市场供需等。
本次作业主要考虑货物重量/体积,以下是具体的计算方式和关键要点:
一、计费重量的确定
空运以实际重量(GrossWeight)和体积重量(VolumeWeight)中的较
高者作为计费重量。
计算公式:
体积重量(kg)= 货物体积(长×宽×高,单位:厘米)÷6000
示例:
若货物实际重量为80kg,体积为120cm×80cm×60cm,则:
体积重量 =(120×80×60)÷6000=96kg
计费重量取96kg(因96kg>80kg)。
二、基础运费计算
1
费率(Rate):航空公司或货代根据航线、货物类型、市场行情等制定(如
CNY30/kg)。本次作业费率与货物类型有关,货物类型分为普通货物、危险货
物和加急货物三种,其费率分别为:
计算公式:基础运费 = 计费重量 × 费率 × 折扣率
其中,折扣率是指不同的用户类型针对每个订单的运费可以享受相应的折扣,
在本题中,用户分为个人用户和集团用户,其中个人用户可享受订单运费的9
折优惠,集团用户可享受订单运费的8折优惠。
三、题目说明
本次题目模拟某客户到该航空公司办理一次货运业务的过程:
航空公司提供如下信息:
航班信息(航班号,航班起飞机场,航班降落机场,航班日期,航班最大载
重量)
2
客户填写货运订单并进行支付,需要提供如下信息:
客户信息(姓名,电话号码等)
货物信息(货物名称,货物包装长、宽、高尺寸,货物重量等)
运送信息(发件人姓名、电话、地址,收件人姓名、电话、地址,所选
航班号,订单日期)
支付方式(支付宝支付、微信支付、现金支付)
注:一个货运订单可以运送多件货物,每件货物均需要根据重量及费率单独
计费。
程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信
息报表及货物明细报表。
四、题目要求
本次题目重点考核面向对象设计原则中的单一职责原则、里氏代换原则、开
闭原则以及合成复用原则、依赖倒转原则,除需要在PTA平台提交源码外,还
需要在超星平台提交本次作业最终得分源码(首次提交最高分源码)的类图,
评判标准为:
基础得分:PTA实际得分
设计因素:单一职责原则(20%)、里氏代换原则(20%)、开闭原则(20%)、
合成复用原则(20%)、依赖倒转原则(20%)。
分析
1. 业务逻辑升级
复合计费模型:
运费计算需同时考虑 货物类型(普通 / 危险 / 加急,对应不同费率)和 用户类型(个人 / 集团,对应 9 折 / 8 折折扣率),公式为:
基础运费 = 计费重量 × 货物类型费率
总运费 = 基础运费 × 用户类型折扣率
(注:每件货物单独计算基础运费,订单总运费为所有货物基础运费之和再乘以折扣率)。
新增支付方式:支持现金支付(共 3 种:支付宝、微信、现金)。
2. 实体与信息结构
客户信息:需区分用户类型(个人 / 集团),可能需要在客户类中新增userType属性。
货物信息:需明确货物类型(普通 / 危险 / 加急),可通过枚举或子类实现。
运送信息:与航班信息关联(航班号需匹配现有航班),需确保订单所选航班存在。
3. 输出要求
生成两份报表:
订单信息报表:包含客户信息、航班信息、总运费、支付方式等。
货物明细报表:每件货物的名称、尺寸、实际重量、体积重量、计费重量、货物类型费率、基础运费等。
代码展示与分析
点击查看代码
import java.util.ArrayList;
import java.util.Objects;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner ac=new Scanner(System.in);
Sender sender;
if(Objects.equals(ac.next(), "Individual")){
sender=new Individual(ac.next(),ac.next(),ac.next(),ac.next());
}else {
sender=new Corporate(ac.next(),ac.next(),ac.next(),ac.next());
}
String a=ac.next();
int n= ac.nextInt();
ArrayList<Cargo> cargos=new ArrayList<>();
for(int i=0;i<n;i++){
if(Objects.equals(a, "Normal")){
Cargo cargo=new Normal(ac.next(),ac.next(), ac.nextDouble(), ac.nextDouble(), ac.nextDouble(), ac.nextDouble());
cargos.add(cargo);
} else if (Objects.equals(a, "Expedite")){
Cargo cargo=new Expedite(ac.next(),ac.next(), ac.nextDouble(), ac.nextDouble(), ac.nextDouble(), ac.nextDouble());
cargos.add(cargo);
}else {
Cargo cargo=new Dangerous(ac.next(),ac.next(), ac.nextDouble(), ac.nextDouble(), ac.nextDouble(), ac.nextDouble());
cargos.add(cargo);
}
}
Flight flight=new Flight(ac.next(), ac.next(), ac.next(), ac.next(), ac.nextInt(), cargos);
if(flight.overload()){
System.out.printf("The flight with flight number:%s has exceeded its load capacity and cannot carry the order.",flight.getFlightNumber());
return;
}
String number=ac.next();
String data= ac.next();
String add1=ac.next();
Consignee consignee1=new fa(ac.next(), ac.next(), add1);
String add2=ac.next();
Consignee consignee2=new shou(ac.next(), ac.next(), add2);
Transport transport=new Transport(consignee1,consignee2,number,data);
Control control=new Control(flight,transport,sender,new Pay(ac.next()));
control.print();
}
}
abstract class Cargo {
private String number;
private String name;//名字
private double length;//长度
private double width;//宽度
private double height;//高度
private double weight;//重量
public Cargo() {
}
public Cargo(String number, String name, double length, double width, double height, double weight) {
this.number = number;
this.name = name;
this.length = length;
this.width = width;
this.height = height;
this.weight = Math.max(length * width * height / 6000.0, weight);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double getMoney() {
return Math.max(length * width * height / 6000.0, weight) * Rates();
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public abstract double Rates();
}
abstract class Consignee {//收
public String name;
public String number;
public String address;
public Consignee() {
}
public Consignee(String name, String number, String address) {
this.name=name;
this.number=number;
this.address=address;
}
public abstract void show();
}
class Control {
private Flight flight;
private Transport transport;
private Sender sender;
private Pay pay;
public Control() {
}
public Control(Flight flight, Transport transport, Sender sender, Pay pay) {
this.flight = flight;
this.transport = transport;
this.sender = sender;
this.pay = pay;
}
public void print() {
sender.show();
System.out.println("订单信息如下:");
System.out.println("-----------------------------------------");
System.out.println("航班号:" + flight.getFlightNumber());
transport.show();
System.out.printf("订单总重量(kg):%.1f\n", flight.allWeight());
System.out.printf("%s金额:%.1f\n\n",pay.put() ,flight.allMoney()*sender.sale());
System.out.println("货物明细如下:");
System.out.println("-----------------------------------------");
System.out.println("明细编号 货物名称 计费重量 计费费率 应交运费");
for (int i = 0; i < flight.getCargos().size(); i++) {
System.out.printf("%d %s %.1f %.1f %.1f\n", i + 1, flight.getCargos().get(i).getName(), flight.getCargos().get(i).getWeight(), flight.getCargos().get(i).Rates(), flight.getCargos().get(i).getMoney());
}
}
}
class fa extends Consignee {
public fa() {
}
public fa(String name, String number, String address) {
super(name, number, address);
}
@Override
public void show() {
System.out.println("发件人姓名:" + name);
System.out.println("发件人电话:" + number);
System.out.println("发件人地址:" + address);
}
}
class Flight {//航班信息
private String flightNumber;//航班号
private String upCity;//起飞城市
private String downCity;//降落城市
private String data;//航班日期
private int maxLoad;//航班最大载重
private ArrayList<Cargo> cargos = new ArrayList<>();
public Flight() {
}
public Flight(String flightNumber, String upCity, String downCity, String data, int maxLoad, ArrayList<Cargo> cargos) {
this.flightNumber = flightNumber;
this.upCity = upCity;
this.downCity = downCity;
this.data = data;
this.maxLoad = maxLoad;
this.cargos = cargos;
}
public String getFlightNumber() {
return flightNumber;
}
public void setFlightNumber(String flightNumber) {
this.flightNumber = flightNumber;
}
public String getUpCity() {
return upCity;
}
public void setUpCity(String upCity) {
this.upCity = upCity;
}
public String getDownCity() {
return downCity;
}
public void setDownCity(String downCity) {
this.downCity = downCity;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public int getMaxLoad() {
return maxLoad;
}
public void setMaxLoad(int maxLoad) {
this.maxLoad = maxLoad;
}
public ArrayList<Cargo> getCargos() {
return cargos;
}
public void setCargos(ArrayList<Cargo> cargos) {
this.cargos = cargos;
}
public boolean overload() {
return allWeight() > maxLoad;
}
public double allWeight() {
double allWeight = 0.0;
for (Cargo cargo : cargos) {
allWeight += cargo.getWeight();
}
return allWeight;
}
public double allMoney() {
double allMoney = 0.0;
for (Cargo cargo : cargos) {
allMoney += cargo.getMoney();
}
return allMoney;
}
}
abstract class Sender{//寄
String go;
public String name;
public String number;
public String address;
public Sender() {
}
public Sender(String go, String name, String number, String address) {
this.name=name;
this.number=number;
this.address=address;
this.go = go;
}
public void show() {
System.out.print("客户:" + name + "(" + number + ")");
}
public abstract double sale();
}
class shou extends Consignee {
public shou() {
}
public shou(String name, String number, String address) {
super(name, number, address);
}
@Override
public void show() {
System.out.println("收件人姓名:" + name);
System.out.println("收件人电话:" + number);
System.out.println("收件人地址:" + address);
}
}
class Transport {//订单信息
private Consignee fa;
private Consignee shou;
private String number;
private String data;
public Transport(Consignee fa, Consignee consignee, String number, String data) {
this.fa = fa;
this.shou = consignee;
this.number = number;
this.data = data;
}
public Consignee getFa() {
return fa;
}
public void setFa(Consignee fa) {
this.fa = fa;
}
public Consignee getShou() {
return shou;
}
public void setShou(Consignee shou) {
this.shou = shou;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public void show() {
System.out.println("订单号:" + number);
System.out.println("订单日期:" + data);
fa.show();
shou.show();
}
}
class Pay {
private String type;
public Pay() {
}
public Pay(String type) {
this.type = type;
}
public String put(){
if(Objects.equals(type, "Wechat")){
return "微信支付";
} else if (Objects.equals(type, "ALiPay")) {
return "支付宝支付";
}else if(Objects.equals(type, "Cash")){
return "现金支付";
}
return null;
}
}
class Individual extends Sender{//普通用户
public Individual() {
}
public Individual(String go, String name, String number, String address) {
super(go, name, number, address);
}
@Override
public double sale() {
return 0.9;
}
}
class Corporate extends Sender{
public Corporate() {
}
public Corporate(String go, String name, String number, String address) {
super(go, name, number, address);
}
@Override
public double sale() {
return 0.8;
}
}
class Normal extends Cargo{
public Normal() {
}
public Normal(String number, String name, double length, double width, double height, double weight) {
super(number, name, length, width, height, weight);
}
@Override
public double Rates() {
double weight=Math.max(getLength()*getWeight()*getHeight()/6000.0,getWeight());
if(weight<20){
return 35;
} else if (weight>=20&&weight<50) {
return 30;
} else if (weight>=50&&weight<100) {
return 25;
}else {
return 15;
}
}
}
class Expedite extends Cargo{
public Expedite() {
}
public Expedite(String number, String name, double length, double width, double height, double weight) {
super(number, name, length, width, height, weight);
}
@Override
public double Rates() {
double weight=Math.max(getLength()*getWeight()*getHeight()/6000.0,getWeight());
if(weight<20){
return 60;
} else if (weight>=20&&weight<50) {
return 50;
} else if (weight>=50&&weight<100) {
return 40;
}else {
return 30;
}
}
}
class Dangerous extends Cargo{
public Dangerous() {
}
public Dangerous(String number, String name, double length, double width, double height, double weight) {
super(number, name, length, width, height, weight);
}
@Override
public double Rates() {
double weight=Math.max(getLength()*getWeight()*getHeight()/6000.0,getWeight());
if(weight<20){
return 80;
} else if (weight>=20&&weight<50) {
return 50;
} else if (weight>=50&&weight<100) {
return 30;
}else {
return 20;
}
}
}
类图

分析结果

点击查看分析结果
Metrics Details For File 'Main.java'
--------------------------------------------------------------------------------------------
Parameter Value
========= =====
Project Directory D:\java_code\pta\src\__5\
Project Name shiyan1
Checkpoint Name Baseline
File Name Main.java
Lines 485
Statements 137
Percent Branch Statements 7.3
Method Call Statements 76
Percent Lines with Comments 1.2
Classes and Interfaces 7
Methods per Class 4.29
Average Statements per Method 2.60
Line Number of Most Complex Method 8
Name of Most Complex Method Main.main()
Maximum Complexity 8
Line Number of Deepest Block 21
Maximum Block Depth 4
Average Block Depth 1.64
Average Complexity 1.28
--------------------------------------------------------------------------------------------
Most Complex Methods in 7 Class(es): Complexity, Statements, Max Depth, Calls
Cargo.Cargo() 1, 6, 2, 1
Cargo.Cargo() 1, 0, 0, 0
Cargo.getHeight() 1, 1, 2, 0
Cargo.getLength() 1, 1, 2, 0
Cargo.getMoney() 1, 1, 2, 1
Cargo.getName() 1, 1, 2, 0
Cargo.getNumber() 1, 1, 2, 0
Cargo.getWeight() 1, 1, 2, 0
Cargo.getWidth() 1, 1, 2, 0
Cargo.setHeight() 1, 1, 2, 0
Cargo.setLength() 1, 1, 2, 0
Cargo.setName() 1, 1, 2, 0
Cargo.setNumber() 1, 1, 2, 0
Cargo.setWeight() 1, 1, 2, 0
Cargo.setWidth() 1, 1, 2, 0
Consignee.Consignee() 1, 3, 2, 0
Consignee.Consignee() 1, 0, 0, 0
Control.Control() 1, 4, 2, 0
Control.Control() 1, 0, 0, 0
Control.print() 2, 6, 3, 10
fa.fa() 1, 1, 2, 1
fa.fa() 1, 0, 0, 0
fa.show() 1, 3, 2, 3
Main.main() 8, 32, 4, 49
Pay.Pay() 1, 1, 2, 0
Pay.Pay() 1, 0, 0, 0
shou.shou() 1, 1, 2, 1
shou.shou() 1, 0, 0, 0
shou.show() 1, 5, 2, 5
--------------------------------------------------------------------------------------------
Block Depth Statements
0 11
1 48
2 63
3 9
4 6
5 0
6 0
7 0
8 0
9+ 0
--------------------------------------------------------------------------------------------
一、整体代码质量总结
规模与结构
代码行数(485 行):较第一题增加 114 行,主要因新增用户类型、货物类型、支付方式的逻辑,但类数增加 7 个类。
方法数量(30 个方法):平均每个类 4.29 个方法,分布均匀。
二、关键问题分析
1. 复杂度与可读性
- 分支语句占比(7.3%):较第一题(2.8%)显著增加,可能因新增业务逻辑(如多类型判断)导致代码分支膨胀,需警惕 “面条式代码”。
2.代码可读性与可维护性不足
- 注释比例极低:仅1.2% 的行含注释,关键逻辑(如折扣率、费率计算)无注释,维护困难。
- 冗余构造方法:
Cargo、Consignee、Control等类存在无逻辑的空构造方法(语句数为 0),可能为测试残留或设计冗余。 - 方法命名模糊:
fa.show()、shou.show()等方法名缺乏语义,难以快速定位功能(如可能为 “发货人”“收货人” 相关逻辑)。
3.设计原则合规性风险
- 依赖倒转原则(DIP):
若直接使用IndividualUser、AlipayPayment具体类,而非接口 / 抽象类,高层模块依赖具体实现。 - 解决方法:定义User抽象类、PaymentStrategy接口,通过接口注入依赖。
- 开闭原则(OCP):
新增货物类型需修改Main中if-else逻辑,而非通过继承扩展。 - 解决方法:使用策略模式,定义CargoTypeStrategy接口,新增类型实现接口即可。
三、解决问题总结
| 问题类型 | 具体建议 | 设计原则关联 |
|---|---|---|
| 缺乏抽象层 | 定义User、CargoTypeStrategy、PaymentStrategy接口 | 依赖倒转、开闭原则 |
| 条件判断冗余 | 使用工厂模式 / 策略模式替代if-else,集中管理类型创建与逻辑判断 | 开闭原则、合成复用原则 |
| 代码可读性差 | 添加关键逻辑注释,重命名模糊方法(如fa.show()→SenderInfo.print()) | 代码可维护性 |
当前代码在设计原则合规性与代码质量上存在抽象层缺失、注释不足等核心问题。通过分层设计、策略模式、工厂模式重构,可显著提升系统扩展性,确保符合五大设计原则。建议优先重构主方法,实现输入 / 业务 / 输出分离,再逐步完善接口与抽象类设计,最终移除冗余代码并补充注释,提升整体可维护性。
三、总结
通过这次做迭代题,我认识到了自己的不足,并且让我学会了使用工厂类。以后更加要注意在关键的地方写注释,同时要多多运用接口和抽象类以便实现解耦合,保证自己的代码更加规范。

浙公网安备 33010602011771号