题目集8~9的总结

前言:
本次题目集八相较于题目集九要偏简单。题目集八点与面的设计是在题目集六的基础上多加了继承和多态,而题目集九则是在八的基础上对题目的类设计进行重构,增加容器类保存点、线、面对象,并对该容器进行相应增、删、遍历操作,加大了题目的难度。题目集八主要考察的是继承与多态的问题,而航空题目的部分则是以类的设计为主,并不需要什么太多的算法,这需要满足单一职责原则,里氏代换原则,开闭原则,合成复用原则即可。题目集九则是在继承与多态的知识点上还需要用到抽象类等知识。每次的题目集中都有前几次题目集当中的迭代问题,题目量虽然不是很大,但是每一道题目都需要我们认真的去思考。题目给了我们类图,这样就让我们在写题目的时候就可以轻松许多,有了参考,以及该往哪方面去想,使我们的思维更加缜密。在难度方面,我个人认为这一次的迭代问题比上一次要简单一点,上一次需要考虑的问题偏多,没有什么经验,这一次的迭代就比上一次就要轻松一些了。
设计与分析:
我们首先来看一下点与线的:
下面是题目八的

点击查看代码
import java.util.Scanner;

// 抽象类Solid
abstract class Solid {
    protected double side;

    public Solid() {}

    public Solid(double side) {
        this.side = side;
    }

    public double getSide() {
        return side;
    }

    public void setSide(double side) {
        this.side = side;
    }

    public abstract double getArea();

    public abstract double getVolume();
}

// 正方体类Cube,继承自Solid
class Cube extends Solid {
    public Cube() {}

    public Cube(double side) {
        super(side);
    }

    @Override
    public double getArea() {
        return 6 * side * side;
    }

    @Override
    public double getVolume() {
        return side * side * side;
    }
}

// 正棱锥类RegularPyramid,继承自Solid
class RegularPyramid extends Solid {
    public RegularPyramid() {}

    public RegularPyramid(double side) {
        super(side);
    }

    // 正三棱锥底面为正三角形,面积公式:sqrt(3) / 4 * a^2 ,这里a为边长
    // 侧面积每个三角形面积为:sqrt(3) / 4 * a^2 ,正三棱锥有3个侧面
    // 总表面积 = 底面积 + 侧面积 = 4 * sqrt(3) / 4 * a^2 = sqrt(3) * a^2
    @Override
    public double getArea() {
        return Math.sqrt(3) * side * side;
    }

    // 正三棱锥体积公式:sqrt(2) / 12 * a^3 ,这里a为边长
    @Override
    public double getVolume() {
        return Math.sqrt(2) / 12 * side * side * side;
    }
}

// 抽象类RubikCube
abstract class RubikCube {
    protected String color;
    protected int layer;
    protected Solid solid;

    public RubikCube() {}

    public RubikCube(String color, int layer, Solid solid) {
        this.color = color;
        this.layer = layer;
        this.solid = solid;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getLayer() {
        return layer;
    }

    public void setLayer(int layer) {
        this.layer = layer;
    }

    public Solid getSolid() {
        return solid;
    }

    public void setSolid(Solid solid) {
        this.solid = solid;
    }

    public abstract double getArea();

    public abstract double getVolume();
}

// 正方体魔方类SquareCube,继承自RubikCube
class SquareCube extends RubikCube {
    public SquareCube() {}

    public SquareCube(String color, int layer, Solid solid) {
        super(color, layer, solid);
    }

    @Override
    public double getArea() {
        // 魔方边长 = 阶数 * 单元边长
        double sideLength = layer * solid.getSide();
        return solid.getArea() * layer * layer;
    }

    @Override
    public double getVolume() {
        double sideLength = layer * solid.getSide();
        return solid.getVolume() * layer * layer * layer;
    }
}

// 正三棱锥魔方类RegularPyramidCube,继承自RubikCube
class RegularPyramidCube extends RubikCube {
    public RegularPyramidCube() {}

    public RegularPyramidCube(String color, int layer, Solid solid) {
        super(color, layer, solid);
    }

    @Override
    public double getArea() {
        double sideLength = layer * solid.getSide();
        return solid.getArea() * layer * layer;
    }

    @Override
    public double getVolume() {
        double sideLength = layer * solid.getSide();
        return solid.getVolume() * layer * layer * layer;
    }
}

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

        String color = input.next();
        int layer = input.nextInt();
        double side = input.nextDouble();

        RubikCube cube1 = new SquareCube(color, layer, new Cube(side));

        color = input.next();
        layer = input.nextInt();
        side = input.nextDouble();

        RubikCube cube2 = new RegularPyramidCube(color, layer, new RegularPyramid(side));

        display(cube1);
        display(cube2);
    }

    public static void display(RubikCube cube) {
        System.out.println(cube.getColor());
        System.out.printf("%.2f\n", cube.getArea());
        System.out.printf("%.2f\n", cube.getVolume());
    }
}
下面是题目九的
点击查看代码
import java.util.Scanner;

// 抽象类Element
abstract class Element {
    public abstract void display();
}

// 点类Point,继承自Element
class Point extends Element {
    private double x;
    private double y;

    public Point() {}

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }

    @Override
    public void display() {
        System.out.println("(" + String.format("%.2f", x) + "," + String.format("%.2f", y) + ")");
    }
}

// 线类Line,继承自Element
class Line extends Element {
    private Point point1;
    private Point point2;
    private String color;

    public Line() {}

    public Line(Point p1, Point p2, String color) {
        this.point1 = p1;
        this.point2 = p2;
        this.color = color;
    }

    public Point getPoint1() {
        return point1;
    }

    public void setPoint1(Point point1) {
        this.point1 = point1;
    }

    public Point getPoint2() {
        return point2;
    }

    public void setPoint2(Point point2) {
        this.point2 = point2;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getDistance() {
        double dx = point2.getX() - point1.getX();
        double dy = point2.getY() - point1.getY();
        return Math.sqrt(dx * dx + dy * dy);
    }

    @Override
    public void display() {
        System.out.println("The line's color is:" + color);
        System.out.println("The line's begin point's Coordinate is:");
        point1.display();
        System.out.println("The line's end point's Coordinate is:");
        point2.display();
        System.out.println("The line's length is:" + String.format("%.2f", getDistance()));
    }
}

// 面类Plane,继承自Element
class Plane extends Element {
    private String color;

    public Plane() {}

    public Plane(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public void display() {
        System.out.println("The Plane's color is:" + color);
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            double x1 = input.nextDouble();
            double y1 = input.nextDouble();
            double x2 = input.nextDouble();
            double y2 = input.nextDouble();
            String color = input.next();

            Point p1 = new Point(x1, y1);
            Point p2 = new Point(x2, y2);
            Line line = new Line(p1, p2, color);
            Plane plane = new Plane(color);

            Element element;

            element = p1;
            element.display();

            element = p2;
            element.display();

            element = line;
            element.display();

            element = plane;
            element.display();
        } catch (Exception e) {
            System.out.println("Wrong Format");
        }
    }
}
设计分析 类的设计 1. Element类:作为抽象父类,定义抽象方法`display()` ,是多态实现的关键基础。它将`Point`、`Line`、`Plane`这些具有不同展示行为的对象统一抽象,使它们在调用`display()`方法时有统一的外部调用形式,提高了代码的可扩展性和可维护性。比如未来若新增图形类,只要继承`Element`并实现`display()`方法,就能无缝融入现有体系。 2. Point类:继承自`Element`,封装了点的横、纵坐标属性,以及相关的访问和修改方法。`display()`方法用于格式化输出点的坐标。它专注于点这一基本几何元素的属性和行为表示,是构建更复杂几何对象(如`Line`)的基础。 3. Line类:继承自`Element`,包含两个`Point`对象表示起止点和颜色属性,有计算线段长度的方法`getDistance()` 。`display()`方法整合了线的颜色、起止点坐标及长度信息的输出。它通过组合`Point`类来描述线的特征,体现了面向对象中组合的设计思想,同时通过重写`display()`方法实现多态。 4. Plane类:继承自`Element`,仅有颜色属性,`display()`方法输出面的颜色。它相对简单,主要是为了满足题目中对不同几何对象统一多态展示的要求,丰富了类层次结构。

方法设计

  1. display()方法:在抽象类Element中声明为抽象方法,各个子类重写该方法实现各自特定的展示逻辑。这种设计符合多态的定义,即同一方法名在不同对象上有不同的行为表现。通过父类引用调用display()方法时,能根据实际指向的子类对象执行相应的展示代码,增强了代码的灵活性和可读性。
  2. 其他方法:如Point类的属性访问器和修改器方法,Line类的getDistance()方法等,这些方法都是围绕类所代表的几何对象的属性和行为来设计,遵循了面向对象中数据封装和模块化的原则,将对象的操作封装在类内部,外部通过接口(方法)进行访问和交互。

功能分析

  1. 输入处理:通过Scanner获取用户输入,在Main类的main方法中进行输入值的读取和对象创建。同时使用try - catch块捕获可能的输入异常,当输入格式不符合要求(如输入非数值类型等)时,能友好地提示Wrong Format,保证了程序的健壮性。

  2. 多态实现:利用Element类的引用分别指向不同子类对象(PointLinePlane),然后调用display()方法。这样在运行时,根据实际对象类型执行对应的display()实现代码,实现了多态特性。例如,同样是调用display()方法,Point对象展示坐标,Line对象展示线的综合信息,Plane对象展示面的颜色,体现了多态在代码复用和灵活性方面的优势。

  3. 几何信息处理:Point类准确表示点坐标,Line类通过计算两点间距离得到线段长度,在展示时能完整输出几何对象的相关属性信息,满足了对“点与线”相关几何信息展示的功能需求。

    接下来我们来看魔方的:

点击查看代码
import java.util.Scanner;

abstract class Solid {
    protected double side;

    public Solid() {}

    public Solid(double side) {
        this.side = side;
    }

    public double getSide() {
        return side;
    }

    public void setSide(double side) {
        this.side = side;
    }

    public abstract double getArea();

    public abstract double getVolume();
}
class Cube extends Solid {
    public Cube() {}

    public Cube(double side) {
        super(side);
    }

    @Override
    public double getArea() {
        return 6 * side * side;
    }

    @Override
    public double getVolume() {
        return side * side * side;
    }
}
class RegularPyramid extends Solid {
    public RegularPyramid() {}

    public RegularPyramid(double side) {
        super(side);
    }

    @Override
    public double getArea() {
        return Math.sqrt(3) * side * side;
    }
    @Override
    public double getVolume() {
        return Math.sqrt(2) / 12 * side * side * side;
    }
}
abstract class RubikCube {
    protected String color;
    protected int layer;
    protected Solid solid;

    public RubikCube() {}

    public RubikCube(String color, int layer, Solid solid) {
        this.color = color;
        this.layer = layer;
        this.solid = solid;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getLayer() {
        return layer;
    }

    public void setLayer(int layer) {
        this.layer = layer;
    }

    public Solid getSolid() {
        return solid;
    }

    public void setSolid(Solid solid) {
        this.solid = solid;
    }

    public abstract double getArea();

    public abstract double getVolume();
}
class SquareCube extends RubikCube {
    public SquareCube() {}

    public SquareCube(String color, int layer, Solid solid) {
        super(color, layer, solid);
    }

    @Override
    public double getArea() {
        double sideLength = layer * solid.getSide();
        return solid.getArea() * layer * layer;
    }

    @Override
    public double getVolume() {
        double sideLength = layer * solid.getSide();
        return solid.getVolume() * layer * layer * layer;
    }
}
class RegularPyramidCube extends RubikCube {
    public RegularPyramidCube() {}

    public RegularPyramidCube(String color, int layer, Solid solid) {
        super(color, layer, solid);
    }

    @Override
    public double getArea() {
        double sideLength = layer * solid.getSide();
        return solid.getArea() * layer * layer;
    }

    @Override
    public double getVolume() {
        double sideLength = layer * solid.getSide();
        return solid.getVolume() * layer * layer * layer;
    }
}

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

        String color = input.next();
        int layer = input.nextInt();
        double side = input.nextDouble();

        RubikCube cube1 = new SquareCube(color, layer, new Cube(side));

        color = input.next();
        layer = input.nextInt();
        side = input.nextDouble();

        RubikCube cube2 = new RegularPyramidCube(color, layer, new RegularPyramid(side));

        display(cube1);
        display(cube2);
    }

    public static void display(RubikCube cube) {
        System.out.println(cube.getColor());
        System.out.printf("%.2f\n", cube.getArea());
        System.out.printf("%.2f\n", cube.getVolume());
    }
}
类的设计分析 1. Solid类 抽象性与通用性:作为抽象类,它定义了立体图形的基本属性`side`(边长)以及获取和设置边长的方法,还有抽象方法`getArea()`(获取表面积)和`getVolume()`(获取体积) 。这为后续具体的立体图形类(如`Cube`和`RegularPyramid`)提供了统一的抽象基础,确保不同立体图形在面积和体积计算等核心操作上有规范的接口定义,增强了代码的通用性和可扩展性。 代码复用性:通过继承`Solid`类,`Cube`和`RegularPyramid`类可以复用`side`属性以及相关的访问和设置方法,避免了重复代码的编写,提高了开发效率。 2. Cube类与RegularPyramid类 继承与特性实现:它们继承自`Solid`类,分别实现了正方体和正三棱锥的表面积和体积计算方法。这种继承关系使得它们既能复用`Solid`类的通用属性和方法,又能针对自身立体图形的特性实现特定的计算逻辑。例如,`Cube`类根据正方体的几何特性,使用公式$6a^2$计算表面积,$a^3$计算体积($a$为边长);`RegularPyramid`类则依据正三棱锥的几何性质,运用相应公式计算表面积和体积。 多态基础:它们对`Solid`类中抽象方法的实现,为后续魔方相关类的多态操作奠定了基础。在更上层的魔方类中,可以通过父类`Solid`的引用指向`Cube`或`RegularPyramid`对象,从而实现多态调用其面积和体积计算方法。 3. RubikCube类 魔方抽象定义:作为抽象类,它定义了魔方的通用属性`color`(颜色)、`layer`(阶数)、`solid`(具体的立体图形对象) ,以及相应的访问和设置方法,还有抽象方法`getArea()`和`getVolume()` 。这是对魔方这一概念的抽象建模,将魔方的共性特征进行统一封装,为具体的魔方子类(如`SquareCube`和`RegularPyramidCube`)提供了规范和基础。 多态桥梁:它的存在使得不同类型的魔方(正方体魔方和正三棱锥魔方)能够在统一的抽象层面上进行操作,通过继承和重写抽象方法,实现不同魔方类型在面积和体积计算展示等行为上的多态表现。 4. SquareCube类与RegularPyramidCube类 魔方类型实现:它们继承自`RubikCube`类,分别实现了正方体魔方和正三棱锥魔方的特定功能。在实现过程中,考虑到魔方边长与阶数、单元边长的关系,根据各自立体图形的面积和体积公式,结合魔方的阶数进行计算。例如,在计算正方体魔方的表面积和体积时,先根据阶数和单元边长确定魔方的实际边长,再代入正方体的面积和体积公式进行计算。 多态体现:通过重写`RubikCube`类的`getArea()`和`getVolume()`方法,当使用`RubikCube`类的引用指向`SquareCube`或`RegularPyramidCube`对象时,能够根据实际对象类型调用对应的面积和体积计算方法,实现多态特性。

功能设计分析

  1. 输入处理:在Main类的main方法中,使用Scanner类从键盘读取用户输入的魔方颜色、阶数和单元边长信息。通过依次读取不同类型的输入值,为创建相应的魔方对象提供必要的数据,确保程序能够根据用户的输入构建出准确的魔方实例。
  2. 多态实现:利用RubikCube类的引用分别指向SquareCubeRegularPyramidCube对象,然后调用display方法。在display方法中,根据实际指向的魔方对象类型,调用对应的getArea()getVolume()方法,实现了多态输出。这种多态设计使得程序在处理不同类型魔方时更加灵活,代码结构更加清晰,也方便后续对不同类型魔方进行扩展和维护。
  3. 魔方属性与计算:程序准确地处理了魔方的三个属性(颜色、阶数、类型),并根据魔方的类型(正方体魔方或正三棱锥魔方),结合其对应的立体图形(正方体或正三棱锥)的几何特性,计算出魔方的表面积和体积。在计算过程中,考虑到魔方边长与阶数、单元边长的关系,通过合理的公式应用,保证了计算结果的准确性,最终按照要求的格式输出魔方的颜色、表面积和体积。
    最后来看航空货运管理系统的:
    这是题目八的:
点击查看代码
import java.util.*;

// 支付接口
interface Payment {
    String pay(double amount);
}

// 微信支付实现
class WeChatPayment implements Payment {
    @Override
    public String pay(double amount) {
        return String.format("微信支付金额:%.1f", amount);
    }
}

// 支付宝支付实现
class AliPayPayment implements Payment {
    @Override
    public String pay(double amount) {
        return String.format("支付宝支付金额:%.1f", amount);
    }
}

// 现金支付实现
class CashPayment implements Payment {
    @Override
    public String pay(double amount) {
        return String.format("现金支付金额:%.1f", amount);
    }
}

// 货物接口
interface Cargo {
    double calculateChargeableWeight();
    double calculateBaseFee();
    String getName();
    double getWeight();
}

// 普通货物
class NormalCargo implements Cargo {
    private String id;
    private String name;
    private double length;
    private double width;
    private double height;
    private double weight;

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

    @Override
    public double calculateChargeableWeight() {
        double volumeWeight = (length * width * height) / 6000;
        return Math.max(weight, volumeWeight);
    }

    @Override
    public double calculateBaseFee() {
        double chargeableWeight = calculateChargeableWeight();
        if (chargeableWeight < 20) return 35;
        else if (chargeableWeight < 50) return 30;
        else if (chargeableWeight < 100) return 25;
        else return 15;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public double getWeight() {
        return weight;
    }
}

// 加急货物
class ExpediteCargo implements Cargo {
    private String id;
    private String name;
    private double length;
    private double width;
    private double height;
    private double weight;

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

    @Override
    public double calculateChargeableWeight() {
        double volumeWeight = (length * width * height) / 6000;
        return Math.max(weight, volumeWeight);
    }

    @Override
    public double calculateBaseFee() {
        double chargeableWeight = calculateChargeableWeight();
        if (chargeableWeight < 20) return 60;
        else if (chargeableWeight < 50) return 50;
        else if (chargeableWeight < 100) return 40;
        else return 30;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public double getWeight() {
        return weight;
    }
}

// 危险货物
class DangerousCargo implements Cargo {
    private String id;
    private String name;
    private double length;
    private double width;
    private double height;
    private double weight;

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

    @Override
    public double calculateChargeableWeight() {
        double volumeWeight = (length * width * height) / 6000;
        return Math.max(weight, volumeWeight);
    }

    @Override
    public double calculateBaseFee() {
        double chargeableWeight = calculateChargeableWeight();
        if (chargeableWeight < 20) return 80;
        else if (chargeableWeight < 50) return 50;
        else if (chargeableWeight < 100) return 30;
        else return 20;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public double getWeight() {
        return weight;
    }
}

// 客户类
class Client {
    private String clientType;
    private String clientId;
    private String name;
    private String phone;
    private String address;

    public Client(String clientType, String clientId, String name, String phone, String address) {
        this.clientType = clientType;
        this.clientId = clientId;
        this.name = name;
        this.phone = phone;
        this.address = address;
    }

    public double getDiscountRate() {
        return clientType.equals("Corporate") ? 0.8 : 0.9;
    }

    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }
}

// 航班类
class Flight {
    private String flightNumber;
    private String departureAirport;
    private String arrivalAirport;
    private String date;
    private double maxLoadCapacity;
    private double currentLoad;

    public Flight(String flightNumber, String departureAirport, String arrivalAirport, String date, double maxLoadCapacity) {
        this.flightNumber = flightNumber;
        this.departureAirport = departureAirport;
        this.arrivalAirport = arrivalAirport;
        this.date = date;
        this.maxLoadCapacity = maxLoadCapacity;
        this.currentLoad = 0;
    }

    public boolean canCarry(double weight) {
        return currentLoad + weight <= maxLoadCapacity;
    }

    public void addLoad(double weight) {
        currentLoad += weight;
    }

    public String getFlightNumber() {
        return flightNumber;
    }
}

// 订单类
class Order {
    private String orderId;
    private String date;
    private String senderName;
    private String senderPhone;
    private String senderAddress;
    private String receiverName;
    private String receiverPhone;
    private String receiverAddress;
    private Client client;
    private Flight flight;
    private Payment payment;
    private List<Cargo> cargos;

    public Order(String orderId, String date, String senderName, String senderPhone, String senderAddress,
                String receiverName, String receiverPhone, String receiverAddress, Client client, Flight flight,
                Payment payment, List<Cargo> cargos) {
        this.orderId = orderId;
        this.date = date;
        this.senderName = senderName;
        this.senderPhone = senderPhone;
        this.senderAddress = senderAddress;
        this.receiverName = receiverName;
        this.receiverPhone = receiverPhone;
        this.receiverAddress = receiverAddress;
        this.client = client;
        this.flight = flight;
        this.payment = payment;
        this.cargos = cargos;
    }

    public double calculateTotalWeight() {
        return cargos.stream().mapToDouble(Cargo::getWeight).sum();
    }

    public double calculateTotalFee() {
        double total = cargos.stream()
                .mapToDouble(c -> c.calculateChargeableWeight() * c.calculateBaseFee() * client.getDiscountRate())
                .sum();
        return total;
    }

    public String generateOrderReport() {
        StringBuilder sb = new StringBuilder();
        sb.append("客户:").append(client.getName()).append("(").append(client.getPhone()).append(")订单信息如下:\n");
        sb.append("-----------------------------------------\n");
        sb.append("航班号:").append(flight.getFlightNumber()).append("\n");
        sb.append("订单号:").append(orderId).append("\n");
        sb.append("订单日期:").append(date).append("\n");
        sb.append("发件人姓名:").append(senderName).append("\n");
        sb.append("发件人电话:").append(senderPhone).append("\n");
        sb.append("发件人地址:").append(senderAddress).append("\n");
        sb.append("收件人姓名:").append(receiverName).append("\n");
        sb.append("收件人电话:").append(receiverPhone).append("\n");
        sb.append("收件人地址:").append(receiverAddress).append("\n");
        sb.append("订单总重量(kg):").append(String.format("%.1f", calculateTotalWeight())).append("\n");
        sb.append(payment.pay(calculateTotalFee())).append("\n");
        return sb.toString();
    }

    public String generateCargoDetails() {
        StringBuilder sb = new StringBuilder();
        sb.append("货物明细如下:\n");
        sb.append("-----------------------------------------\n");
        sb.append("明细编号    货物名称    计费重量    计费费率    应交运费\n");
        
        int index = 1;
        for (Cargo cargo : cargos) {
            double chargeableWeight = cargo.calculateChargeableWeight();
            double baseFee = cargo.calculateBaseFee();
            double fee = chargeableWeight * baseFee * client.getDiscountRate();
            
            sb.append(index).append("    ")
              .append(cargo.getName()).append("    ")
              .append(String.format("%.1f", chargeableWeight)).append("    ")
              .append(String.format("%.1f", baseFee)).append("    ")
              .append(String.format("%.1f", fee)).append("\n");
            index++;
        }
        
        return sb.toString();
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取客户信息
        String clientType = scanner.nextLine();
        String clientId = scanner.nextLine();
        String clientName = scanner.nextLine();
        String clientPhone = scanner.nextLine();
        String clientAddress = scanner.nextLine();
        Client client = new Client(clientType, clientId, clientName, clientPhone, clientAddress);
        
        // 读取货物信息
        String cargoType = scanner.nextLine();
        int cargoCount = Integer.parseInt(scanner.nextLine());
        List<Cargo> cargos = new ArrayList<>();
        
        for (int i = 0; i < cargoCount; i++) {
            String cargoId = scanner.nextLine();
            String cargoName = scanner.nextLine();
            double width = Double.parseDouble(scanner.nextLine());
            double length = Double.parseDouble(scanner.nextLine());
            double height = Double.parseDouble(scanner.nextLine());
            double weight = Double.parseDouble(scanner.nextLine());
            
            Cargo cargo;
            switch (cargoType) {
                case "Normal":
                    cargo = new NormalCargo(cargoId, cargoName, length, width, height, weight);
                    break;
                case "Expedite":
                    cargo = new ExpediteCargo(cargoId, cargoName, length, width, height, weight);
                    break;
                case "Dangerous":
                    cargo = new DangerousCargo(cargoId, cargoName, length, width, height, weight);
                    break;
                default:
                    throw new IllegalArgumentException("Invalid cargo type");
            }
            cargos.add(cargo);
        }
        
        // 读取航班信息
        String flightNumber = scanner.nextLine();
        String departureAirport = scanner.nextLine();
        String arrivalAirport = scanner.nextLine();
        String flightDate = scanner.nextLine();
        double maxLoadCapacity = Double.parseDouble(scanner.nextLine());
        Flight flight = new Flight(flightNumber, departureAirport, arrivalAirport, flightDate, maxLoadCapacity);
        
        // 检查航班载重
        double totalWeight = cargos.stream().mapToDouble(Cargo::getWeight).sum();
        if (!flight.canCarry(totalWeight)) {
            System.out.printf("The flight with flight number:%s has exceeded its load capacity and cannot carry the order.", flightNumber);
            return;
        }
        
        // 读取订单信息
        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 paymentMethod = scanner.nextLine();
        
        Payment payment;
        switch (paymentMethod) {
            case "Wechat":
                payment = new WeChatPayment();
                break;
            case "ALiPay":
                payment = new AliPayPayment();
                break;
            case "Cash":
                payment = new CashPayment();
                break;
            default:
                throw new IllegalArgumentException("Invalid payment method");
        }
        
        // 创建订单
        Order order = new Order(orderId, orderDate, senderName, senderPhone, senderAddress,
                               receiverName, receiverPhone, receiverAddress, client, flight, payment, cargos);
        
        // 输出结果
        System.out.print(order.generateOrderReport());
        System.out.print(order.generateCargoDetails());
    }
}
这是题目九的:
点击查看代码
import java.util.*;

interface Payment {
    String pay(double amount);
}

class WeChatPayment implements Payment {
    @Override
    public String pay(double amount) {
        return String.format("微信支付金额:%.1f", amount);
    }
}

class AliPayPayment implements Payment {
    @Override
    public String pay(double amount) {
        return String.format("支付宝支付金额:%.1f", amount);
    }
}
class CashPayment implements Payment {
    @Override
    public String pay(double amount) {
        return String.format("现金支付金额:%.1f", amount);
    }
}

interface Cargo {
    double calculateChargeableWeight();
    double calculateBaseFee();
    String getName();
    double getWeight();
}

class NormalCargo implements Cargo {
    private String id;
    private String name;
    private double length;
    private double width;
    private double height;
    private double weight;

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

    @Override
    public double calculateChargeableWeight() {
        double volumeWeight = (length * width * height) / 6000;
        return Math.max(weight, volumeWeight);
    }

    @Override
    public double calculateBaseFee() {
        double chargeableWeight = calculateChargeableWeight();
        if (chargeableWeight < 20) return 35;
        else if (chargeableWeight < 50) return 30;
        else if (chargeableWeight < 100) return 25;
        else return 15;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public double getWeight() {
        return weight;
    }
}

class ExpediteCargo implements Cargo {
    private String id;
    private String name;
    private double length;
    private double width;
    private double height;
    private double weight;

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

    @Override
    public double calculateChargeableWeight() {
        double volumeWeight = (length * width * height) / 6000;
        return Math.max(weight, volumeWeight);
    }

    @Override
    public double calculateBaseFee() {
        double chargeableWeight = calculateChargeableWeight();
        if (chargeableWeight < 20) return 60;
        else if (chargeableWeight < 50) return 50;
        else if (chargeableWeight < 100) return 40;
        else return 30;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public double getWeight() {
        return weight;
    }
}

class DangerousCargo implements Cargo {
    private String id;
    private String name;
    private double length;
    private double width;
    private double height;
    private double weight;

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

    @Override
    public double calculateChargeableWeight() {
        double volumeWeight = (length * width * height) / 6000;
        return Math.max(weight, volumeWeight);
    }

    @Override
    public double calculateBaseFee() {
        double chargeableWeight = calculateChargeableWeight();
        if (chargeableWeight < 20) return 80;
        else if (chargeableWeight < 50) return 50;
        else if (chargeableWeight < 100) return 30;
        else return 20;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public double getWeight() {
        return weight;
    }
}

class Client {
    private String clientType;
    private String clientId;
    private String name;
    private String phone;
    private String address;

    public Client(String clientType, String clientId, String name, String phone, String address) {
        this.clientType = clientType;
        this.clientId = clientId;
        this.name = name;
        this.phone = phone;
        this.address = address;
    }

    public double getDiscountRate() {
        return clientType.equals("Corporate") ? 0.8 : 0.9;
    }

    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }
}

class Flight {
    private String flightNumber;
    private String departureAirport;
    private String arrivalAirport;
    private String date;
    private double maxLoadCapacity;
    private double currentLoad;

    public Flight(String flightNumber, String departureAirport, String arrivalAirport, String date, double maxLoadCapacity) {
        this.flightNumber = flightNumber;
        this.departureAirport = departureAirport;
        this.arrivalAirport = arrivalAirport;
        this.date = date;
        this.maxLoadCapacity = maxLoadCapacity;
        this.currentLoad = 0;
    }

    public boolean canCarry(double weight) {
        return currentLoad + weight <= maxLoadCapacity;
    }

    public void addLoad(double weight) {
        currentLoad += weight;
    }

    public String getFlightNumber() {
        return flightNumber;
    }
}

class Order {
    private String orderId;
    private String date;
    private String senderName;
    private String senderPhone;
    private String senderAddress;
    private String receiverName;
    private String receiverPhone;
    private String receiverAddress;
    private Client client;
    private Flight flight;
    private Payment payment;
    private List<Cargo> cargos;

    public Order(String orderId, String date, String senderName, String senderPhone, String senderAddress,
                String receiverName, String receiverPhone, String receiverAddress, Client client, Flight flight,
                Payment payment, List<Cargo> cargos) {
        this.orderId = orderId;
        this.date = date;
        this.senderName = senderName;
        this.senderPhone = senderPhone;
        this.senderAddress = senderAddress;
        this.receiverName = receiverName;
        this.receiverPhone = receiverPhone;
        this.receiverAddress = receiverAddress;
        this.client = client;
        this.flight = flight;
        this.payment = payment;
        this.cargos = cargos;
    }

    public double calculateTotalWeight() {
        return cargos.stream().mapToDouble(Cargo::getWeight).sum();
    }

public double calculateTotalFee() {
    double total = cargos.stream()
            .mapToDouble(c -> c.calculateChargeableWeight() * c.calculateBaseFee())
            .sum();
    return total * client.getDiscountRate();
}



    public String generateOrderReport() {
        StringBuilder sb = new StringBuilder();
        sb.append("客户:").append(client.getName()).append("(").append(client.getPhone()).append(")订单信息如下:\n");
        sb.append("-----------------------------------------\n");
        sb.append("航班号:").append(flight.getFlightNumber()).append("\n");
        sb.append("订单号:").append(orderId).append("\n");
        sb.append("订单日期:").append(date).append("\n");
        sb.append("发件人姓名:").append(senderName).append("\n");
        sb.append("发件人电话:").append(senderPhone).append("\n");
        sb.append("发件人地址:").append(senderAddress).append("\n");
        sb.append("收件人姓名:").append(receiverName).append("\n");
        sb.append("收件人电话:").append(receiverPhone).append("\n");
        sb.append("收件人地址:").append(receiverAddress).append("\n");
        sb.append("订单总重量(kg):").append(String.format("%.1f", calculateTotalWeight())).append("\n");
        sb.append(payment.pay(calculateTotalFee())).append("\n\n");
        return sb.toString();
    }

    public String generateCargoDetails() {
        StringBuilder sb = new StringBuilder();
        sb.append("货物明细如下:\n");
        sb.append("-----------------------------------------\n");
        sb.append("明细编号\t货物名称\t计费重量\t计费费率\t应交运费\n");
        
        int index = 1;
        for (Cargo cargo : cargos) {
            double chargeableWeight = cargo.calculateChargeableWeight();
            double baseFee = cargo.calculateBaseFee();
            double fee = chargeableWeight * baseFee;
            
            sb.append(index).append("\t")
              .append(cargo.getName()).append("\t")
              .append(String.format("%.1f", chargeableWeight)).append("\t") 
              .append(String.format("%.1f", baseFee)).append("\t")
              .append(String.format("%.1f", fee)).append("\n");
            index++;
        }
        
        return sb.toString();
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        String clientType = scanner.nextLine();
        String clientId = scanner.nextLine();
        String clientName = scanner.nextLine();
        String clientPhone = scanner.nextLine();
        String clientAddress = scanner.nextLine();
        Client client = new Client(clientType, clientId, clientName, clientPhone, clientAddress);
        
        String cargoType = scanner.nextLine();
        int cargoCount = Integer.parseInt(scanner.nextLine());
        List<Cargo> cargos = new ArrayList<>();
        
        for (int i = 0; i < cargoCount; i++) {
            String cargoId = scanner.nextLine();
            String cargoName = scanner.nextLine();
            double width = Double.parseDouble(scanner.nextLine());
            double length = Double.parseDouble(scanner.nextLine());
            double height = Double.parseDouble(scanner.nextLine());
            double weight = Double.parseDouble(scanner.nextLine());
            
            Cargo cargo;
            switch (cargoType) {
                case "Normal":
                    cargo = new NormalCargo(cargoId, cargoName, length, width, height, weight);
                    break;
                case "Expedite":
                    cargo = new ExpediteCargo(cargoId, cargoName, length, width, height, weight);
                    break;
                case "Dangerous":
                    cargo = new DangerousCargo(cargoId, cargoName, length, width, height, weight);
                    break;
                default:
                    throw new IllegalArgumentException("Invalid cargo type");
            }
            cargos.add(cargo);
        }
        
        String flightNumber = scanner.nextLine();
        String departureAirport = scanner.nextLine();
        String arrivalAirport = scanner.nextLine();
        String flightDate = scanner.nextLine();
        double maxLoadCapacity = Double.parseDouble(scanner.nextLine());
        Flight flight = new Flight(flightNumber, departureAirport, arrivalAirport, flightDate, maxLoadCapacity);
        
        double totalWeight = cargos.stream().mapToDouble(Cargo::getWeight).sum();
        if (!flight.canCarry(totalWeight)) {
            System.out.printf("The flight with flight number:%s has exceeded its load capacity and cannot carry the order.", flightNumber);
            return;
        }
        
        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 paymentMethod = scanner.nextLine();
        
        Payment payment;
        switch (paymentMethod) {
            case "Wechat":
                payment = new WeChatPayment();
                break;
            case "ALiPay":
                payment = new AliPayPayment();
                break;
            case "Cash":
                payment = new CashPayment();
                break;
            default:
                throw new IllegalArgumentException("Invalid payment method");
        }
        
        // 创建订单
        Order order = new Order(orderId, orderDate, senderName, senderPhone, senderAddress,
                               receiverName, receiverPhone, receiverAddress, client, flight, payment, cargos);
        
        // 输出结果
        System.out.print(order.generateOrderReport());
        System.out.print(order.generateCargoDetails());
    }
}
题目一分析:基础运费计算 设计要点 计费重量计算: 比较实际重量和体积重量,取较大者 体积重量公式:(长×宽×高)÷6000 费率结构: 三种货物类型:普通、危险、加急 每种类型按重量区间设置不同费率 示例:普通货物<20kg费率为35,20-50kg费率为30等 折扣机制: 个人用户9折,集团用户8折 基础运费=计费重量×费率×折扣率 类设计分析 Cargo类: 属性:长、宽、高、重量、类型 方法:计算计费重量、计算基础运费 Client类: 属性:类型(个人/集团)、折扣率 方法:获取折扣率 Order类: 组合Cargo和Client 计算总运费 计算示例分析 以输入样例为例: 发电机(Expedite): 尺寸:80×60×40cm → 体积重量=192kg 实际重量80kg → 计费重量取192kg 但根据代码实现,实际计算为80kg(需确认实现是否正确) 信号发生器(Expedite): 尺寸:55×70×60cm → 体积重量=385kg 实际重量45kg → 计费重量取385kg 但代码中按45kg计算(需确认) 题目二分析:完整系统实现 系统架构 核心类: Payment接口(支付方式) Cargo接口(货物类型) Client(客户信息) Flight(航班信息) Order(订单管理) 设计原则应用: 单一职责:每个类职责明确 开闭原则:通过接口扩展新类型 里氏替换:子类可替换父类 依赖倒置:高层模块依赖抽象 合成复用:优先使用组合 关键流程 输入处理: 读取客户、货物、航班、订单信息 创建相应对象 业务逻辑: 检查航班载重能力 计算各货物运费 应用客户折扣 输出生成: 订单摘要 货物明细 在写代码时遇到的问题: 计费重量计算问题: 原代码中直接使用实际重量,未比较体积重量 修正:实现体积重量计算并取较大值 运费计算不一致: 明细中显示折扣前金额,总结显示折扣后金额 修正:统一使用折扣后金额 输入处理: 需要严格按输入顺序读取数据 处理多货物输入时需循环读取


一、数据类型与输入处理
魔方问题:输入时需接收多种数据类型,像魔方颜色(字符串)、阶数(整数)、边长(浮点数) 。起初未考虑输入错误情况,比如输入非数字字符替代数值,程序直接报错崩溃。后来在代码中添加try - catch块捕获异常,若输入格式不符,友好提示错误,增强了程序健壮性。
点线问题:同样存在输入多种类型数据的情况。在读取点的横纵坐标(浮点数)、颜色(字符串)等时,未做格式校验,导致输入混乱时程序异常。改进方法是先验证输入数据格式是否正确,再进行后续操作,确保数据可靠性。
二、继承与多态的实现
魔方问题:在设计类层次结构实现多态时,对抽象类Solid和RubikCube的抽象方法定义和子类重写理解不深。子类重写方法时,方法签名未严格与抽象方法一致,导致多态调用失败。仔细核对方法名、参数列表和返回值类型后,才正确实现多态,让不同魔方类型能按预期计算和展示面积、体积。
点线问题:将Point、Line、Plane类继承自抽象类Element来实现多态,起初在Element类引用指向子类对象调用display()方法时,出现错误。经排查发现是对父类引用调用子类重写方法的机制掌握不牢,未确保子类重写方法符合多态规则,调整后成功实现不同几何对象的多态展示。
三、几何计算与逻辑处理
魔方问题:计算魔方表面积和体积时,因魔方边长由阶数和单元边长决定,公式推导和代码实现易出错。如正方体魔方表面积计算,未正确考虑阶数与单元边长关系,导致结果错误。反复核对几何公式,理清逻辑后才得到准确结果。
点线问题:Line类中计算线段长度,使用两点间距离公式,在处理坐标差值计算和平方根运算时,数据精度和运算顺序需特别注意。开始因未处理好精度问题,导致长度计算结果有偏差,通过合理使用格式化输出和检查运算逻辑解决了该问题。、

  1. 计费重量计算的理解偏差
    坑点描述:最初没有完全理解题目中"以实际重量和体积重量中的较高者作为计费重量"这一规则,直接使用了实际重量进行计算。

问题表现:

对于体积较大的货物,运费计算明显偏低

与预期结果不符,特别是轻抛货(体积大但重量轻)的情况

解决方案:

java
// 修正后的计费重量计算方法
public double calculateChargeableWeight() {
double volumeWeight = (length * width * height) / 6000;
return Math.max(weight, volumeWeight); // 取实际重量和体积重量的较大值
}
心得:

必须仔细阅读题目需求,特别是业务规则部分

对专业术语(如"体积重量")要准确理解

可以先用纸笔计算几个测试用例验证理解是否正确

  1. 折扣应用不一致问题
    坑点描述:在订单总运费和货物明细运费计算中,折扣应用方式不一致,导致最终金额对不上。

问题表现:

订单总金额显示的是折扣后金额

货物明细中显示的是折扣前金额

用户对账时会产生困惑

解决方案:

java
// 统一应用折扣的计算方式
public double calculateItemFee(Cargo cargo) {
double baseFee = cargo.calculateChargeableWeight() * cargo.calculateBaseFee();
return baseFee * client.getDiscountRate(); // 统一应用折扣
}
心得:

业务规则应在全系统保持一致

金额计算这类核心逻辑最好集中处理

在需求分析阶段就应明确折扣的应用场景

  1. 面向对象设计原则的应用
    坑点描述:初期没有很好遵循SOLID原则,导致代码难以扩展和维护。

具体问题:

将不同货物类型的费率计算硬编码在一个类中

支付方式直接使用条件判断实现

客户折扣逻辑与订单耦合过紧

改进方案:

java
// 使用策略模式处理不同货物类型
public interface Cargo {
double calculateBaseFee();
}

// 不同货物类型实现各自费率计算
public class ExpediteCargo implements Cargo {
public double calculateBaseFee() {
// 加急货物特定费率计算
}
}
心得:
开闭原则(OCP)确实能提高系统可扩展性
依赖倒置(DIP)使高层模块不依赖低层细节
单一职责(SRP)让每个类更易理解和维护
设计模式不是银弹,但要学会识别适用场景
4. 输入输出格式处理
坑点描述:没有严格按照题目要求的格式处理输入输出,导致PTA平台判题失败。
常见问题:
输入顺序错误,读取数据错位
输出格式中空格、换行不符合要求
数字精度不统一(有时保留1位小数,有时不保留)
解决方案:

点击查看代码
// 严格遵循输出格式要求
System.out.printf("明细编号\t货物名称\t计费重量\t计费费率\t应交运费%n");
System.out.printf("%d\t%s\t%.1f\t%.1f\t%.1f%n", 
    index, 
    cargo.getName(),
    chargeableWeight,
    baseFee,
    fee);
心得: 自动化判题系统对格式要求极其严格 使用printf等格式化输出方法比字符串拼接更可靠 开发过程中就要用题目给的样例测试输出格式 5. 航班载重校验的时机 坑点描述:最初在订单创建后才检查航班载重,导致无效订单被创建。 问题表现: 即使航班无法承载,订单对象也已生成 业务逻辑顺序不合理 改进方案:
点击查看代码
// 在创建订单前先校验载重
double totalWeight = calculateTotalWeight(cargos);
if (!flight.canCarry(totalWeight)) {
    System.out.printf("航班%s已超载%n", flight.getNumber());
    return;
}
// 校验通过才创建订单
Order order = new Order(...);
心得: 业务逻辑的校验要前置 避免创建无效的业务对象 异常情况处理要放在主要业务流程之前 6. 测试用例设计不足 坑点描述:初期只测试了"happy path",没有考虑边界情况和异常输入。 遗漏的测试场景: 体积重量>实际重量的情况 刚好处于费率分界点的重量(如49.9kg vs 50kg) 最大载重临界值测试 非法输入(负数重量、非数值输入等) 改进方法:
点击查看代码
// 添加边界测试用例
@Test
public void testChargeableWeightBoundary() {
    // 体积重量≈实际重量
    Cargo cargo = new NormalCargo(..., 60, 50, 40, 20); // 体积重量=20kg
    assertEquals(20, cargo.calculateChargeableWeight(), 0.01);
    
    // 实际重量略大于体积重量
    cargo = new NormalCargo(..., 60, 50, 40, 20.1);
    assertEquals(20.1, cargo.calculateChargeableWeight(), 0.01);
}
心得: 边界条件往往最容易出问题 测试用例要覆盖所有业务规则分支 参数化测试能有效提高测试覆盖率 测试代码也要保持良好质量 一、架构设计优化 建议采用清晰的三层架构:

表现层:处理输入输出,格式转换

业务逻辑层:核心运费计算、订单处理

数据访问层:航班、订单等数据的持久化

  1. 引入依赖注入
    java
    // 使用工厂模式创建支付处理器
    public class PaymentFactory {
    public static Payment create(String type) {
    switch(type) {
    case "Wechat": return new WeChatPayment();
    case "ALiPay": return new AliPayPayment();
    case "Cash": return new CashPayment();
    default: throw new IllegalArgumentException();
    }
    }
    }

// 在订单服务中使用
Payment payment = PaymentFactory.create(paymentType);
功能扩展建议

  1. 多级费率体系增强
    java
    // 支持季节性和区域性费率调整
    public interface RateStrategy {
    double adjustBaseRate(double originalRate, LocalDate date, String route);
    }

// 实现类示例
public class HolidayRateStrategy implements RateStrategy {
public double adjustBaseRate(double originalRate, LocalDate date, String route) {
return isHoliday(date) ? originalRate * 1.2 : originalRate;
}
}
2. 货物类型扩展机制
java
// 通过配置文件动态加载货物类型
@Configuration
@PropertySource("classpath:cargo-types.properties")
public class CargoConfig {
@Value("#{${cargo.types}}")
private Map<String, String> cargoTypes;

// 注册所有货物类型处理器
@Bean
public Map<String, CargoHandler> cargoHandlers() {
// 实现动态加载
}
}
三、用户体验改进

  1. 交互式命令行界面
    java
    // 改进后的用户交互流程
    public void startInteractiveMode() {
    Scanner sc = new Scanner(System.in);
    System.out.println("请选择操作:");
    System.out.println("1. 创建新订单");
    System.out.println("2. 查询订单状态");
    System.out.println("3. 航班信息查询");

    int choice = sc.nextInt();
    switch(choice) {
    case 1: createOrderInteractive(sc); break;
    // 其他选项处理
    }
    }

  2. 结果可视化输出
    java
    // 生成ASCII表格输出
    public void printCargoTable(List cargos) {
    System.out.println("+----+------------+---------+---------+---------+");
    System.out.println("| ID | 货物名称 | 重量 | 费率 | 运费 |");
    System.out.println("+----+------------+---------+---------+---------+");

    cargos.forEach(c -> {
    System.out.printf("| %2d | %-10s | %7.1f | %7.1f | %7.1f |%n",
    c.getId(), c.getName(),
    c.getWeight(), c.getRate(), c.getFee());
    });

    System.out.println("+----+------------+---------+---------+---------+");
    }
    四、性能优化建议

  3. 航班载重预计算
    java
    // 使用缓存预计算航班剩余容量
    public class FlightCapacityCache {
    private Map<String, Double> capacityMap = new ConcurrentHashMap<>();

    public boolean checkCapacity(String flightNo, double weight) {
    return capacityMap.compute(flightNo, (k, v) -> {
    double remaining = (v == null) ? getFromDB(flightNo) : v;
    return remaining - weight;
    }) >= 0;
    }
    }

  4. 批量处理优化
    java
    // 使用并行流处理大批量货物计算
    public double calculateTotalFee(List cargos) {
    return cargos.parallelStream()
    .mapToDouble(c -> c.calculateChargeableWeight()
    * c.getRate()
    * getDiscount())
    .sum();
    }
    五、异常处理增强

  5. 自定义异常体系
    java
    // 定义业务异常层次
    public abstract class ShippingException extends RuntimeException {
    public ShippingException(String message) {
    super(message);
    }
    }

public class OverweightException extends ShippingException {
public OverweightException(double max) {
super("超过最大载重限制: " + max + "kg");
}
}
2. 异常处理建议
java
// 统一的异常处理机制
@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(OverweightException.class)
public ResponseEntity handleOverweight(OverweightException ex) {
return ResponseEntity.badRequest()
.body("错误: " + ex.getMessage());
}

@ExceptionHandler(InputException.class)
public ResponseEntity handleInputError(InputException ex) {
return ResponseEntity.badRequest()
.body("输入错误: " + ex.getMessage());
}
}
六、测试覆盖率提升

  1. 参数化测试示例
    java
    @RunWith(Parameterized.class)
    public class FeeCalculationTest {

    @Parameters
    public static Collection<Object[]> data() {
    return Arrays.asList(new Object[][] {
    { "Normal", 15, 35 }, // 普通货物15kg
    { "Normal", 25, 30 }, // 普通货物25kg
    { "Dangerous", 10, 80 } // 危险品10kg
    });
    }

    @Test
    public void testRateCalculation() {
    // 测试逻辑
    }
    }

  2. 边界测试建议
    java
    // 临界值测试用例设计
    @Test
    public void testWeightBoundaries() {
    // 费率分界点测试
    testRate(19.9, 35); // 普通货物<20kg
    testRate(20.0, 30); // 普通货物≥20kg
    testRate(49.9, 30); // 普通货物<50kg
    testRate(50.0, 25); // 普通货物≥50kg
    }
    七、部署与维护建议
    配置化管理:

将费率表、折扣规则等移至外部配置文件

支持热更新不重启应用

监控指标:

java
// 使用Micrometer添加监控
@Bean
public MeterRegistryCustomizer metrics() {
return registry -> {
registry.gauge("flight.capacity.usage", flightService,
s -> s.getCapacityUsageRatio());
};
}
文档自动化:

使用Swagger生成API文档

维护CHANGELOG记录版本变更

总结
这些改进建议从多个维度提升了系统的:

可维护性:通过分层设计和清晰架构

扩展性:支持新货物类型和费率策略

健壮性:完善的异常处理和边界检查

用户体验:更友好的交互界面

性能:批量处理和缓存优化

  1. 核心技术掌握
    面向对象设计原则:深入理解了SOLID原则在实际项目中的应用价值,特别是:

单一职责原则使代码更易维护

开闭原则提高了系统扩展性

依赖倒置降低了模块耦合度

设计模式实践:成功应用了策略模式(货物类型处理)、工厂模式(支付方式创建)等常用模式

异常处理体系:构建了层次化的业务异常处理机制

  1. 工程能力提升
    测试驱动开发:认识到先写测试用例对需求澄清的重要性

持续重构:体验了迭代式改进对代码质量的提升效果

API设计:学习了如何设计易用且可扩展的接口

  1. 业务理解深化
    掌握了航空货运的核心业务规则:

计费重量计算逻辑

多维度费率体系

航班载重管理机制

posted @ 2025-05-25 12:16  不会小猫  阅读(46)  评论(0)    收藏  举报