第二次blog作业

前言
知识点总结

  • 题目集8:主要涉及面向对象编程的基础概念,如类的定义、封装、继承和多态。在“航空货运管理系统”中,需要定义多个类,如Customer、Goods、Flight和Order,并通过类的组合来实现系统功能。还涉及到基本的输入输出操作,以及简单的条件判断和循环语句。
  • 题目集9:在题目集8的基础上,进一步深化了面向对象编程的应用,引入了抽象类、接口和策略模式。通过抽象类Custome和Goods,实现了不同类型客户和货物的多态性。使用接口PaymentStrategy实现了不同支付方式的策略模式,提高了代码的可扩展性和可维护性。同时,还涉及到流处理和格式化输出的知识。

设计与分析

题目集8:
航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明参看说明文件。
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

源代码:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

class Customer {
private String id;
private String name;
private String phone;
private String address;

public Customer(String id, String name, String phone, String address) {
    this.id = id;
    this.name = name;
    this.phone = phone;
    this.address = address;
}

public String getName() { return name; }
public String getPhone() { return phone; }

}

class Goods {
private String id;
private String name;
private double width;
private double length;
private double height;
private double grossWeight;

public Goods(String id, String name, double width, double length, double height, double grossWeight) {
    this.id = id;
    this.name = name;
    this.width = width;
    this.length = length;
    this.height = height;
    this.grossWeight = grossWeight;
}

public double calculateVolumeWeight() {
    return (length * width * height) / 6000.0;
}

public double getChargeWeight() {
    return Math.max(grossWeight, calculateVolumeWeight());
}

public double determineRate() {
    double cw = getChargeWeight();
    if (cw < 20) return 35.0;
    else if (cw < 50) return 30.0;
    else if (cw < 100) return 25.0;
    else return 15.0;
}

public double computeFreight() {
    return getChargeWeight() * determineRate();
}

public String getName() { return name; }

}

class Flight {
private String number;
private String departure;
private String arrival;
private String date;
private double maxWeight;

public Flight(String number, String departure, String arrival, String date, double maxWeight) {
    this.number = number;
    this.departure = departure;
    this.arrival = arrival;
    this.date = date;
    this.maxWeight = maxWeight;
}

public String getNumber() { return number; }
public double getMaxWeight() { return maxWeight; }

}

class Order {
private String orderId;
private String orderDate;
private String senderAddress;
private String senderName;
private String senderPhone;
private String receiverAddress;
private String receiverName;
private String receiverPhone;
private Flight flight;
private Customer customer;
private List goodsList;

public Order(String orderId, String orderDate, String senderAddress, String senderName, String senderPhone,
             String receiverAddress, String receiverName, String receiverPhone, Flight flight, Customer customer,
             List<Goods> goodsList) {
    this.orderId = orderId;
    this.orderDate = orderDate;
    this.senderAddress = senderAddress;
    this.senderName = senderName;
    this.senderPhone = senderPhone;
    this.receiverAddress = receiverAddress;
    this.receiverName = receiverName;
    this.receiverPhone = receiverPhone;
    this.flight = flight;
    this.customer = customer;
    this.goodsList = goodsList;
}

public double calculateTotalWeight() {
    double total = 0;
    for (Goods g : goodsList) {
        total += g.getChargeWeight();
    }
    return total;
}

public boolean checkWeightLimit() {
    double total = calculateTotalWeight();
    if (total > flight.getMaxWeight()) {
        System.out.printf("The flight with flight number:%s has exceeded its load capacity and cannot carry the order.\n", flight.getNumber());
        return false;
    }
    return true;
}

public void generateOrderReport() {
    System.out.printf("客户:%s(%s)订单信息如下:\n", customer.getName(), customer.getPhone());
    System.out.println("-----------------------------------------");
    System.out.printf("航班号:%s\n", flight.getNumber());
    System.out.printf("订单号:%s\n", orderId);
    System.out.printf("订单日期:%s\n", orderDate);
    System.out.printf("发件人姓名:%s\n", senderName);
    System.out.printf("发件人电话:%s\n", senderPhone);
    System.out.printf("发件人地址:%s\n", senderAddress);
    System.out.printf("收件人姓名:%s\n", receiverName);
    System.out.printf("收件人电话:%s\n", receiverPhone);
    System.out.printf("收件人地址:%s\n", receiverAddress);
    double totalWeight = calculateTotalWeight();
    System.out.printf("订单总重量(kg):%.1f\n", totalWeight);
    double totalFreight = 0;
    for (Goods g : goodsList) {
        totalFreight += g.computeFreight();
    }
    System.out.printf("微信支付金额:%.1f\n\n", totalFreight);

    System.out.println("货物明细如下:");
    System.out.println("-----------------------------------------");
    System.out.println("明细编号    货物名称    计费重量    计费费率    应交运费");
    for (int i = 0; i < goodsList.size(); i++) {
        Goods g = goodsList.get(i);
        double cw = g.getChargeWeight();
        double rate = g.determineRate();
        double freight = g.computeFreight();
        System.out.printf("%d    %-10s    %.1f    %.1f    %.1f\n", i + 1, g.getName(), cw, rate, freight);
    }
}

}

public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);

    String customerId = scanner.nextLine().trim();
    String customerName = scanner.nextLine().trim();
    String customerPhone = scanner.nextLine().trim();
    String customerAddress = scanner.nextLine().trim();

    int goodsCount = Integer.parseInt(scanner.nextLine());
    List<Goods> goodsList = new ArrayList<>();
    for (int i = 0; i < goodsCount; i++) {
        String goodsId = scanner.nextLine().trim();
        String goodsName = scanner.nextLine().trim();
        double width = Double.parseDouble(scanner.nextLine());
        double length = Double.parseDouble(scanner.nextLine());
        double height = Double.parseDouble(scanner.nextLine());
        double grossWeight = Double.parseDouble(scanner.nextLine());
        goodsList.add(new Goods(goodsId, goodsName, width, length, height, grossWeight));
    }

    String flightNumber = scanner.nextLine().trim();
    String departure = scanner.nextLine().trim();
    String arrival = scanner.nextLine().trim();
    String flightDate = scanner.nextLine().trim();
    double maxWeight = Double.parseDouble(scanner.nextLine());
    Flight flight = new Flight(flightNumber, departure, arrival, flightDate, maxWeight);

    String orderId = scanner.nextLine().trim();
    String orderDate = scanner.nextLine().trim();
    String senderAddress = scanner.nextLine().trim();
    String senderName = scanner.nextLine().trim();
    String senderPhone = scanner.nextLine().trim();
    String receiverAddress = scanner.nextLine().trim();
    String receiverName = scanner.nextLine().trim();
    String receiverPhone = scanner.nextLine().trim();

    Customer customer = new Customer(customerId, customerName, customerPhone, customerAddress);
    Order order = new Order(orderId, orderDate, senderAddress, senderName, senderPhone,
            receiverAddress, receiverName, receiverPhone, flight, customer, goodsList);

    if (!order.checkWeightLimit()) {
        return;
    }
}

}
分析:

Main.java 文件包含 4 个类 / 接口,代码行数 205 行,语句数 118,注释比例为 0.0%(缺乏必要注释,可读性待提升)。最复杂方法为 Goods.determineRate(),其复杂度为 5(条件判断较多,逻辑集中),行数 47,块深度 3,反映该方法处理多分支费率计算时的高内聚性,但可维护性不足。类的方法数平均 4 个,每个方法平均语句数 6.13,整体结构较简洁,但核心逻辑方法(如 determineRate())需优化。

题目集9:
航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明参看说明文件。
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位小数。

输入样例:
在这里给出一组输入。例如:

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
输出样例:
在这里给出相应的输出。例如:

客户:郭靖(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

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Scanner;

abstract class Customer {
protected String type;
protected String id;
protected String name;
protected String phone;
protected String address;

public Customer(String type, String id, String name, String phone, String address) {
    this.type = type;
    this.id = id;
    this.name = name;
    this.phone = phone;
    this.address = address;
}

public abstract double getDiscountRate();

}

class IndividualCustomer extends Customer {
public IndividualCustomer(String id, String name, String phone, String address) {
super("Individual", id, name, phone, address);
}

@Override
public double getDiscountRate() {
    return 0.9;
}

}

class CorporateCustomer extends Customer {
public CorporateCustomer(String id, String name, String phone, String address) {
super("Corporate", id, name, phone, address);
}

@Override
public double getDiscountRate() {
    return 0.8;
}

}

abstract class Goods {
protected String id;
protected String name;
protected double width;
protected double length;
protected double height;
protected double actualWeight;

public Goods(String id, String name, double width, double length, double height, double actualWeight) {
    this.id = id;
    this.name = name;
    this.width = width;
    this.length = length;
    this.height = height;
    this.actualWeight = actualWeight;
}

public double calculateVolumeWeight() {
    double volume = width * length * height;
    return volume / 6000;
}

public double calculateChargeWeight() {
    double volumeWeight = calculateVolumeWeight();
    return Math.max(actualWeight, volumeWeight);
}

public abstract double calculateRate();

}

class NormalGoods extends Goods {
public NormalGoods(String id, String name, double width, double length, double height, double actualWeight) {
super(id, name, width, length, height, actualWeight);
}

@Override
public double calculateRate() {
    double chargeWeight = calculateChargeWeight();
    if (chargeWeight < 20) return 35;
    else if (chargeWeight < 50) return 30;
    else if (chargeWeight < 100) return 25;
    else return 15;
}

}

class ExpediteGoods extends Goods {
public ExpediteGoods(String id, String name, double width, double length, double height, double actualWeight) {
super(id, name, width, length, height, actualWeight);
}

@Override
public double calculateRate() {
    double chargeWeight = calculateChargeWeight();
    if (chargeWeight < 20) return 60;
    else if (chargeWeight < 50) return 50;
    else if (chargeWeight < 100) return 40;
    else return 30;
}

}

class DangerousGoods extends Goods {
public DangerousGoods(String id, String name, double width, double length, double height, double actualWeight) {
super(id, name, width, length, height, actualWeight);
}

@Override
public double calculateRate() {
    double chargeWeight = calculateChargeWeight();
    if (chargeWeight < 20) return 80;
    else if (chargeWeight < 50) return 50;
    else if (chargeWeight < 100) return 30;
    else return 20;
}

}

interface PaymentStrategy {
String getPaymentType();
double pay(double amount);
}

class WechatPayment implements PaymentStrategy {
@Override
public String getPaymentType() {
return "微信";
}

@Override
public double pay(double amount) {
    return amount; // 实际支付逻辑可扩展
}

}

class AlipayPayment implements PaymentStrategy {
@Override
public String getPaymentType() {
return "支付宝";
}

@Override
public double pay(double amount) {
    return amount;
}

}

class CashPayment implements PaymentStrategy {
@Override
public String getPaymentType() {
return "现金";
}

@Override
public double pay(double amount) {
    return amount;
}

}

class Flight {
private String flightNo;
private String departureAirport;
private String arrivalAirport;
private String date;
private double maxLoad;

public Flight(String flightNo, String departureAirport, String arrivalAirport, String date, double maxLoad) {
    this.flightNo = flightNo;
    this.departureAirport = departureAirport;
    this.arrivalAirport = arrivalAirport;
    this.date = date;
    this.maxLoad = maxLoad;
}

public boolean isLoadAvailable(double totalWeight) {
    return totalWeight <= maxLoad;
}

public String getFlightNo() { return flightNo; }

}

class Order {
private Customer customer;
private Flight flight;
private String orderId;
private String orderDate;
private String senderName;
private String senderPhone;
private String senderAddress;
private String receiverName;
private String receiverPhone;
private String receiverAddress;
private PaymentStrategy paymentStrategy;
private final ArrayList goodsList = new ArrayList<>();
private final DecimalFormat df = new DecimalFormat("0.0");

public Order(Customer customer, Flight flight, String orderId, String orderDate,
             String senderName, String senderPhone, String senderAddress,
             String receiverName, String receiverPhone, String receiverAddress,
             PaymentStrategy paymentStrategy) {
    this.customer = customer;
    this.flight = flight;
    this.orderId = orderId;
    this.orderDate = orderDate;
    this.senderName = senderName;
    this.senderPhone = senderPhone;
    this.senderAddress = senderAddress;
    this.receiverName = receiverName;
    this.receiverPhone = receiverPhone;
    this.receiverAddress = receiverAddress;
    this.paymentStrategy = paymentStrategy;
}

public void addGoods(Goods goods) {
    goodsList.add(goods);
}

public double calculateTotalWeight() {
    return goodsList.stream().mapToDouble(Goods::calculateChargeWeight).sum();
}

public void generateReport() {
    double totalWeight = calculateTotalWeight();

    if (!flight.isLoadAvailable(totalWeight)) {
        System.out.printf("The flight with flight number:%s has exceeded its load capacity and cannot carry the order.%n",
                flight.getFlightNo());
        return;
    }

    double totalFee = goodsList.stream()
            .mapToDouble(g -> g.calculateChargeWeight() * g.calculateRate())
            .sum();
    double discount = customer.getDiscountRate();
    double paymentAmount = totalFee * discount;

    System.out.printf("客户:%s(%s)订单信息如下:%n", customer.name, customer.phone);
    System.out.println("-----------------------------------------");
    System.out.printf("航班号:%s%n", flight.getFlightNo());
    System.out.printf("订单号:%s%n", orderId);
    System.out.printf("订单日期:%s%n", orderDate);
    System.out.printf("发件人姓名:%s%n", senderName);
    System.out.printf("发件人电话:%s%n", senderPhone);
    System.out.printf("发件人地址:%s%n", senderAddress);
    System.out.printf("收件人姓名:%s%n", receiverName);
    System.out.printf("收件人电话:%s%n", receiverPhone);
    System.out.printf("收件人地址:%s%n", receiverAddress);
    System.out.printf("订单总重量(kg):%s%n", df.format(totalWeight));
    System.out.printf("%s支付金额:%s%n%n", paymentStrategy.getPaymentType(), df.format(paymentAmount));
    System.out.println("货物明细如下:");
    System.out.println("-----------------------------------------");
    System.out.println("明细编号    货物名称    计费重量    计费费率    应交运费");
    for (int i = 0; i < goodsList.size(); i++) {
        Goods goods = goodsList.get(i);
        double chargeWeight = goods.calculateChargeWeight();
        double rate = goods.calculateRate();
        double fee = chargeWeight * rate;
        System.out.printf("%d    %s    %s    %s    %s%n",
                i + 1, goods.name, df.format(chargeWeight), df.format(rate), df.format(fee));
    }
}

}

public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);

    String customerType = sc.next();
    String customerId = sc.next();
    String customerName = sc.next();
    String customerPhone = sc.next();
    String customerAddress = sc.next();

    Customer customer;
    if ("Individual".equals(customerType)) {
        customer = new IndividualCustomer(customerId, customerName, customerPhone, customerAddress);
    } else {
        customer = new CorporateCustomer(customerId, customerName, customerPhone, customerAddress);
    }

    String goodsType = sc.next();
    int goodsCount = sc.nextInt();
    ArrayList<Goods> goodsList = new ArrayList<>();
    for (int i = 0; i < goodsCount; i++) {
        String goodsId = sc.next();
        String goodsName = sc.next();
        double width = sc.nextDouble();
        double length = sc.nextDouble();
        double height = sc.nextDouble();
        double actualWeight = sc.nextDouble();

        Goods goods;
        switch (goodsType) {
            case "Normal":
                goods = new NormalGoods(goodsId, goodsName, width, length, height, actualWeight);
                break;
            case "Expedite":
                goods = new ExpediteGoods(goodsId, goodsName, width, length, height, actualWeight);
                break;
            case "Dangerous":
                goods = new DangerousGoods(goodsId, goodsName, width, length, height, actualWeight);
                break;
            default:
                throw new IllegalArgumentException("Invalid goods type");
        }
        goodsList.add(goods);
    }

    String flightNo = sc.next();
    String departureAirport = sc.next();
    String arrivalAirport = sc.next();
    String flightDate = sc.next();
    double maxLoad = sc.nextDouble();
    Flight flight = new Flight(flightNo, departureAirport, arrivalAirport, flightDate, maxLoad);

    String orderId = sc.next();
    String orderDate = sc.next();
    String senderAddress = sc.next();
    String senderName = sc.next();
    String senderPhone = sc.next();
    String receiverAddress = sc.next();
    String receiverName = sc.next();
    String receiverPhone = sc.next();
    String paymentType = sc.next();

    PaymentStrategy paymentStrategy;
    switch (paymentType) {
        case "Wechat":
            paymentStrategy = new WechatPayment();
            break;
        case "ALiPay":
            paymentStrategy = new AlipayPayment();
            break;
        case "Cash":
            paymentStrategy = new CashPayment();
            break;
        default:
            throw new IllegalArgumentException("Invalid payment type");
    }

    Order order = new Order(customer, flight, orderId, orderDate,
            senderName, senderPhone, senderAddress,
            receiverName, receiverPhone, receiverAddress,
            paymentStrategy);
    goodsList.forEach(order::addGoods);
    order.generateReport();

    sc.close();
}

}

Main.java 文件包含 11 个类 / 接口,代码行数 351,语句数 178,注释比例仅 0.3%(需加强注释)。最复杂方法为 ExpediteGoods.calculateRate(),复杂度 5(处理加急货物费率的多条件判断),行数 81,块深度 6,反映逻辑密集性。类平均方法数 5.64,单个方法平均语句数 0.79(部分方法可优化)。

采坑心得

题目集8

  • 输入格式问题:在读取输入时,由于使用Scanner类,需要注意输入的格式和顺序。如果输入格式不符合要求,可能会导致程序抛出异常或产生错误的结果。例如,在读取整数时,如果输入的不是有效的整数,会抛出NumberFormatException异常。
  • 重量计算问题:在计算货物的计费重量时,需要考虑体积重量和实际重量的大小关系,取较大值作为计费重量。如果忽略了这一点,可能会导致运费计算错误。

题目集9

  • 抽象类和接口的使用:在使用抽象类和接口时,需要正确理解它们的概念和用途。抽象类不能实例化,只能作为基类被继承,而接口是一种特殊的抽象类,只包含抽象方法。在实现抽象类和接口时,需要确保所有的抽象方法都被实现,否则会导致编译错误。
  • 策略模式的应用:在使用策略模式时,需要正确设计和实现策略接口和具体策略类。在选择具体策略时,需要根据实际情况进行判断,避免出现逻辑错误。

改进建议

题目集8

  • 代码复用:可以将一些重复的代码提取成方法,提高代码的复用性。例如,在Order类的generateOrderReport()方法中,有一些格式化输出的代码可以提取成一个单独的方法。
  • 异常处理:在读取输入时,可以增加异常处理机制,提高程序的健壮性。例如,在读取整数时,可以使用try-catch块捕获NumberFormatException异常,并给出相应的提示信息。

题目集9

  • 代码注释:增加代码注释,提高代码的可读性。特别是在使用抽象类、接口和策略模式的地方,需要详细解释代码的功能和设计意图。
  • 单元测试:编写单元测试用例,对各个类和方法进行测试,确保代码的正确性和稳定性。可以使用JUnit等测试框架来进行单元测试。

总结

学习收获

  • 通过本阶段两次题目集的练习,深入理解了面向对象编程的基本概念,如类的定义、封装、继承和多态。
  • 学会了使用抽象类、接口和策略模式来提高代码的可扩展性和可维护性。
  • 掌握了基本的输入输出操作和异常处理机制,提高了程序的健壮性。

进一步学习方向

  • 深入学习设计模式,了解更多的设计模式及其应用场景,提高代码的设计水平。
  • 学习数据库编程,将航空货运管理系统与数据库结合,实现数据的持久化存储和管理。
  • 学习前端开发技术,开发一个可视化的用户界面,提高系统的用户体验。

对课程的建议

  • 增加更多的实践案例和项目,让学生在实际项目中应用所学知识,提高解决实际问题的能力。
  • 加强对设计模式和架构设计的教学,让学生了解如何设计出高质量的软件系统。
  • 提供更多的学习资源和参考资料,帮助学生深入学习和研究相关知识。
posted @ 2025-05-25 14:34  刘昊宇  阅读(29)  评论(0)    收藏  举报