Lib3985

导航

第二次博客作业

一、前言

1. 题目背景

航空货运管理系统是一个模拟航空公司货运业务的系统,主要涉及运费计算订单管理。运费计算基于货物重量/体积,并考虑货物类型、用户类型等影响因素。

2. 两次作业的共同点

考察点 第一次作业 第二次作业
运费计算方式 基于实际重量和体积重量取较大值 相同
计费公式 体积重量 = (长×宽×高) / 6000 相同
订单管理 客户填写订单,包含货物、运送、支付信息 相同
面向对象设计原则 单一职责、里氏替换、开闭原则、合成复用 新增依赖倒置原则
输出要求 生成订单信息报表和货物明细报表 相同

3. 第二次作业的新增要求

新增/调整内容 说明
费率计算方式 第一次采用分段计费(按重量区间),第二次改为基于货物类型(普通、危险、加急)
用户折扣 新增个人用户(9折)和集团用户(8折)
支付方式 第一次仅支持支付宝、微信支付,第二次新增现金支付
设计原则 第一次考察4个原则,第二次新增依赖倒置原则
可扩展性 明确提示用户、支付方式、货物需要可扩展

二:设计与分析:

1.第一次航空货运管理系统程序:

设计:

1.Main类 - 相当于系统的大脑,负责协调各个模块工作
2. Customer类 - 处理客户信息(姓名、电话、地址等)
3. Product类 - 管理货物信息和运费计算
4. Flight类 - 处理航班信息
5. Order类 - 管理订单信息
6. Payment相关类 - 处理支付方式(但我没做具体实现😢)

点击查看代码
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

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

        // 读取客户信息
        int customerID = Integer.parseInt(sc.nextLine().trim());
        String customerName = sc.nextLine().trim();
        String customerPhone = sc.nextLine().trim();
        String customerAddress = sc.nextLine().trim();
        Customer customer = new Customer(customerID, customerName, customerPhone, customerAddress);

        // 读取货物信息
        int goodsNumber = Integer.parseInt(sc.nextLine().trim());
        List<Product> products = new ArrayList<>();
        double totalBillingWeight = 0;

        for (int i = 0; i < goodsNumber; i++) {
            int productID = Integer.parseInt(sc.nextLine().trim());
            String productName = sc.nextLine().trim();
            double width = Double.parseDouble(sc.nextLine().trim());
            double length = Double.parseDouble(sc.nextLine().trim());
            double height = Double.parseDouble(sc.nextLine().trim());
            double weight = Double.parseDouble(sc.nextLine().trim());

            Product product = new Product(i+1, productID, productName, weight, length, width, height);
            double volumeWeight = product.calculateVolumeWeight(length, width, height);
            double billingWeight = Math.max(weight, volumeWeight);
            totalBillingWeight += billingWeight; // 累加计费重量
            products.add(product);
        }

        // 读取航班信息
        String flightID = sc.nextLine().trim();
        String departureCity = sc.nextLine().trim();
        String arrivalCity = sc.nextLine().trim();
        String flightDate = sc.nextLine().trim();
        double maxLoadWeight = Double.parseDouble(sc.nextLine().trim());
        Flight flight = new Flight(flightID, departureCity, arrivalCity, flightDate, maxLoadWeight);

        // 检查航班载重
       if (totalBillingWeight > maxLoadWeight) { 
    System.out.printf("The flight with flight number:%s has exceeded its load capacity and cannot carry the order.", flightID);
    return;
}

        // 读取订单信息
        String orderID = sc.nextLine().trim();
        String orderDate = sc.nextLine().trim();
        String senderAddress = sc.nextLine().trim();
        String senderName = sc.nextLine().trim();
        String senderPhone = sc.nextLine().trim();
        String receiverAddress = sc.nextLine().trim();
        String receiverName = sc.nextLine().trim();
        String receiverPhone = sc.nextLine().trim();

        // 创建订单
        Order order = new Order();
        order.setOrderID(orderID);
        order.setOrderDate(orderDate);
        order.setSendername(senderName);
        order. setSenderphonenumber(senderPhone);
        order.setSenderaddress(senderAddress);
        order.setReceivername(receiverName);
        order.setReceiverphonenumber(receiverPhone);
        order.setReceiveraddress(receiverAddress);
        order.setFlightnumber(flight);

        // 计算运费
        double totalPayment = 0;
        for (Product product : products) {
            double volumeWeight = product.calculateVolumeWeight(product.getLength(), product.getWidth(), product.getHeight());
            double billingWeight = Math.max(product.getWeight(), volumeWeight);
            double freight = product.calculateFreight(billingWeight);
            totalPayment += freight;
        }

    // 输出订单信息
System.out.println("客户:" + customerName + "(" + customerPhone + ")订单信息如下:");
System.out.println("-----------------------------------------");
System.out.println("航班号:" + flightID);
System.out.println("订单号:" + orderID);
System.out.println("订单日期:" + orderDate);
System.out.println("发件人姓名:" + senderName);
System.out.println("发件人电话:" + senderPhone);
System.out.println("发件人地址:" + senderAddress);
System.out.println("收件人姓名:" + receiverName);
System.out.println("收件人电话:" + receiverPhone);
System.out.println("收件人地址:" + receiverAddress);
System.out.println("订单总重量(kg):" + df.format(totalBillingWeight));
System.out.println("微信支付金额:" + df.format(totalPayment));
System.out.println();
System.out.println("货物明细如下:");
System.out.println("-----------------------------------------");
System.out.println("明细编号\t货物名称\t计费重量\t计费费率\t应交运费");

for (Product product : products) {
    double volumeWeight = product.calculateVolumeWeight(
        product.getLength(),
        product.getWidth(),
        product.getHeight()
    );
    double billingWeight = Math.max(product.getWeight(), volumeWeight);
    double freight = product.calculateFreight(billingWeight);
    double rate = freight / billingWeight;

    System.out.printf("%d\t%s\t%.1f\t%.1f\t%.1f%n",
        product.getNumber(),
        product.getProductName(),
        billingWeight,
        rate,
        freight);
}
}
}
class Customer {
  private int customerID;
  private String customerName;
  private String phonenumber;
  private String address;
  public Customer() {}
    public Customer(int customerID, String customerName, String phonenumber, String address) {
      this.customerID = customerID;
      this.customerName = customerName;
      this.phonenumber = phonenumber;
      this.address = address;
    }
  public int getCustomerID() { return customerID; }
  public String getName() { return customerName; }
  public String getPhonenumber() { return phonenumber; }
  public String getAddress() { return address; }

  public void setCustomerID(int customerID) { this.customerID = customerID; }
  public void setName(String name) { this.customerName = name; }
  public void setPhonenumber(String phonenumber) { this.phonenumber = phonenumber; }
  public void setAddress(String address) { this.address = address; }
}

class Product {
    private int number;
    private int productID;
    private String productName;
    private double weight;
    private double length;
    private double width;
    private double height;

    public Product() {
    }

    public Product(int number, int productID, String productName, double weight, double length, double width, double height) {
        this.number = number;
        this.productID = productID;
        this.productName = productName;
        this.weight = weight;
        this.length = length;
        this.width = width;
        this.height = height;
    }

    public int getNumber() {
        return number;
    }

    public int getProductID() {
        return productID;
    }

    public String getProductName() {
        return productName;
    }

    public double getWeight() {
        return weight;
    }

    public double getLength() {
        return length;
    }

    public double getWidth() {
        return width;
    }

    public double getHeight() {
        return height;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public void setProductID(int productID) {
        this.productID = productID;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public void setLength(double length) {
        this.length = length;
    }

    public void setWidth(double width) {
        this.width = width;
    }

    public void setHeight(double height) {
        this.height = height;
    }
    public double calculateVolumeWeight(double length, double width, double height) {
        return (length * width * height)/6000.0;
    }
    public double calculateFreight(double billingWeight) {
        int rate;
        if (billingWeight < 20) {
            rate = 35;
        } else if (billingWeight < 50&&billingWeight >=20) {
            rate = 30;
        } else if (billingWeight >= 50&&billingWeight < 100) {
            rate = 25;
        } else {
            rate = 15;
        }
        return rate * billingWeight;

    }

}

class Flight {
    private String flightID;
    private String departureCity;
    private String arrivalCity;
    private String flightDate;
    private double maxLoadWeight;
    public Flight() {}
    public Flight(String flightID, String departureCity, String arrivalCity, String flightDate, double maxLoadWeight){
        this.flightID = flightID;
        this.departureCity = departureCity;
        this.arrivalCity = arrivalCity;
        this.flightDate = flightDate;
        this.maxLoadWeight = maxLoadWeight;
    }
    public String getFlightID() {return flightID;}
    public String getDepartureCity() {return departureCity;}
    public String getArrivalCity() {return arrivalCity;}
    public String getFlightDate() {return flightDate;}
    public double getMaxLoadWeight() {return maxLoadWeight;}
    public void setFlightID(String flightID) {this.flightID = flightID;}
    public void setDepartureCity(String departureCity) {this.departureCity = departureCity;}
    public void setArrivalCity(String arrivalCity) {this.arrivalCity = arrivalCity;}
    public void setFlightDate(String flightDate) {this.flightDate = flightDate;}
    public void setMaxLoadWeight(double maxLoadWeight) {this.maxLoadWeight = maxLoadWeight;}

}

 class Order {
    private String orderID;
    private String orderDate;
    private String sendername;
    private String senderphonenumber;
    private String senderaddress;
    private String receivername;
    private String receiverphonenumber;
    private String receiveraddress;
    private Flight flightnumber;
    public Order() {}
    public String getOrderID() {return orderID;}
    public void setOrderID(String orderID) {this.orderID = orderID;}

    public String getOrderDate() {return orderDate;}
    public void setOrderDate(String orderDate) {this.orderDate = orderDate;}

    public String getSendername() {return sendername;}
    public void setSendername(String sendername) {this.sendername = sendername;}

    public String getSenderphonenumber() {return senderphonenumber;}
    public void setSenderphonenumber(String senderphonenumber) {
        this.senderphonenumber = senderphonenumber;
    }

    public void setFlightnumber(Flight flightnumber) {
        this.flightnumber = flightnumber;
    }
    public Flight getFlightnumber() {return flightnumber;}

    public String getSenderaddress() {return senderaddress;}
    public void setSenderaddress(String senderaddress) {this.senderaddress = senderaddress;}

    public String getReceivername() {return receivername;}
    public void setReceivername(String receivername) {this.receivername = receivername;}

    public String getReceiverphonenumber() {return receiverphonenumber;}
    public void setReceiverphonenumber(String receiverphonenumber) {this.receiverphonenumber = receiverphonenumber;}

    public String getReceiveraddress() {return receiveraddress;}
    public void setReceiveraddress(String receiveraddress) {this.receiveraddress = receiveraddress;}


}

abstract class Payment {
    public Payment(){}
    public abstract void pay(double amount);
}
class WechatPayment extends Payment {
   @Override
    public void pay(double amount) {

   }
}
class AliPayment extends Payment {
    @Override
    public void pay(double amount) {}
}





类图:

报表内容:

航空货运管理系统代码质量分析

一、核心问题分析

  1. 运费计算模块(Product.java)

public double calculateFreight() {
    if (type == DANGEROUS) {       // 分支1
        if (weight > 50) { ... }   // 分支2
        else if (...) { ... }      // 分支3
    } 
    else if (type == EXPRESS) {    // 分支4
        // ...共7层条件嵌套
    }
}

高复杂度问题

  • 圈复杂度高达7(建议值<5)
  • 包含7层条件嵌套

设计原则违反

  • 违反单一职责原则(SRP)
  • 违反开闭原则(OCP)
主要缺陷:

• 🚨 圈复杂度高达7(建议值<5)
• 🧩 违反单一职责原则(SRP)
• 🔄 新增货物类型需修改核心逻辑

二、质量指标评估

质量指标 当前值 推荐值 评估
方法语句数 30 ≤15 ⚠️ 超标
方法调用次数 60 - ⚠️ 过高

✔ 优势亮点

  • 基础类(Order/Flight)设计规范
  • 支付模块扩展性良好(OCP)
  • 平均嵌套深度1.36(优于行业标准)

2.第二次航空货运管理系统程序

设计:

主要改进亮点

  1. 客户分级处理:现在系统能区分个人客户和集团客户了,个人打9折,集团打8折。这个用到了继承和抽象方法,Customer变成了抽象类,下面有IndividualCustomer和GroupCustomer两个子类。
  2. 货物类型区分:不再是统一费率,现在分成了普通货物、危险品和加急货物三种类型,每种费率不同。这里用了一个很聪明的策略模式(FreightStrategy),把运费计算规则封装成不同的策略类。
  3. 支付方式扩展:支付方式从两种增加到三种(微信、支付宝、现金),而且用接口(PaymentMethod)来定义支付行为,以后要加新的支付方式很方便。
    具体实现分析
  4. 输入处理更灵活:
    ◦ 现在会先读取客户类型和货物类型,再创建对应的对象
    ◦ 用了Java 8的Stream API来计算总重量和总运费,代码更简洁
  5. 运费计算更专业:
    ◦ 每种货物类型有自己的计算策略(NormalStrategy/DangerousCargoStrategy/ExpediteStrategy)
    ◦ 策略类里实现了calculate和getRate两个方法,计算和查询费率分开
  6. 折扣处理更规范:
    ◦ 折扣逻辑放在Customer的子类里实现
    ◦ 调用applyDiscount方法自动应用对应折扣
  7. 报表生成更完整:
    ◦ 单独写了printReport方法处理输出
    ◦ 能正确显示不同支付方式的名称
    ◦ 货物明细表格格式统一
点击查看代码
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

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

        // 读取客户信息
        String customerType = sc.nextLine().trim();
        int customerID = Integer.parseInt(sc.nextLine().trim());
        String customerName = sc.nextLine().trim();
        String customerPhone = sc.nextLine().trim();
        String customerAddress = sc.nextLine().trim();
        Customer customer = customerType.equalsIgnoreCase("Individual") ? 
                new IndividualCustomer(customerID, customerName, customerPhone, customerAddress) :
                new GroupCustomer(customerID, customerName, customerPhone, customerAddress);

        // 读取货物信息
        String cargoType = sc.nextLine().trim();
        int goodsNumber = Integer.parseInt(sc.nextLine().trim());
        List<Product> products = new ArrayList<>();
        
        for (int i = 0; i < goodsNumber; i++) {
            int productID = Integer.parseInt(sc.nextLine().trim());
            String productName = sc.nextLine().trim();
            double width = Double.parseDouble(sc.nextLine().trim());
            double length = Double.parseDouble(sc.nextLine().trim());
            double height = Double.parseDouble(sc.nextLine().trim());
            double weight = Double.parseDouble(sc.nextLine().trim());

            Product product = new Product(i+1, productID, productName, weight, length, width, height);
            product.setCargoType(cargoType);
            products.add(product);
        }

        // 计算总计费重量
        double totalBillingWeight = products.stream()
                .mapToDouble(p -> Math.max(p.getWeight(), p.calculateVolumeWeight()))
                .sum();

        // 读取航班信息
        String flightID = sc.nextLine().trim();
        String departureCity = sc.nextLine().trim();
        String arrivalCity = sc.nextLine().trim();
        String flightDate = sc.nextLine().trim();
        double maxLoadWeight = Double.parseDouble(sc.nextLine().trim());
        Flight flight = new Flight(flightID, departureCity, arrivalCity, flightDate, maxLoadWeight);

        // 检查航班载重
        if (totalBillingWeight > maxLoadWeight) {
            System.out.printf("The flight with flight number:%s has exceeded its load capacity and cannot carry the order.", flightID);
            return;
        }

        // 读取订单信息
        Order order = new Order();
        order.setOrderID(sc.nextLine().trim());
        order.setOrderDate(sc.nextLine().trim());
        order.setSenderaddress(sc.nextLine().trim());  // 发件人地址
        order.setSendername(sc.nextLine().trim());     // 发件人姓名
        order.setSenderphonenumber(sc.nextLine().trim()); // 发件人电话
        order.setReceiveraddress(sc.nextLine().trim()); // 收件人地址
        order.setReceivername(sc.nextLine().trim());   // 收件人姓名
        order.setReceiverphonenumber(sc.nextLine().trim()); // 收件人电话
        order.setFlightnumber(flight);

        // 设置支付方式
        String paymentType = sc.nextLine().trim();
        PaymentMethod payment = paymentType.equalsIgnoreCase("Wechat") ? new WeChatPayment() :
                              paymentType.equalsIgnoreCase("ALiPay") ? new AlipayPayment() : new CashPayment();
        order.setPayment(payment);

        // 计算运费
        double totalPayment = products.stream()
                .mapToDouble(p -> p.calculateFreight(Math.max(p.getWeight(), p.calculateVolumeWeight())))
                .sum();
        totalPayment = customer.applyDiscount(totalPayment);

        // 生成报告
        printReport(customer, order, products, totalBillingWeight, totalPayment, payment);
    }

    private static void printReport(Customer customer, Order order, List<Product> products, 
                                   double totalWeight, double totalPayment, PaymentMethod payment) {
        System.out.println("客户:" + customer.getName() + "(" + customer.getPhonenumber() + ")订单信息如下:");
        System.out.println("-----------------------------------------");
        System.out.println("航班号:" + order.getFlightnumber().getFlightID());
        System.out.println("订单号:" + order.getOrderID());
        System.out.println("订单日期:" + order.getOrderDate());
        System.out.println("发件人姓名:" + order.getSendername());
        System.out.println("发件人电话:" + order.getSenderphonenumber());
        System.out.println("发件人地址:" + order.getSenderaddress());
        System.out.println("收件人姓名:" + order.getReceivername());
        System.out.println("收件人电话:" + order.getReceiverphonenumber());
        System.out.println("收件人地址:" + order.getReceiveraddress());
        System.out.println("订单总重量(kg):" + new DecimalFormat("#.0").format(totalWeight));
        
        // 获取支付方式名称
        String paymentName = payment instanceof WeChatPayment ? "微信" : 
                            payment instanceof AlipayPayment ? "支付宝" : "现金";
        System.out.println(paymentName + "支付金额:" + new DecimalFormat("#.0").format(totalPayment));

        System.out.println("\n货物明细如下:");
        System.out.println("-----------------------------------------");
        System.out.println("明细编号\t货物名称\t计费重量\t计费费率\t应交运费");
        
        for (Product product : products) {
            double billingWeight = Math.max(product.getWeight(), product.calculateVolumeWeight());
            double freight = product.calculateFreight(billingWeight);
            double rate = product.getFreightRate(billingWeight);
            System.out.printf("%d\t%s\t%.1f\t%.1f\t%.1f%n",
                    product.getNumber(),
                    product.getProductName(),
                    billingWeight,
                    rate,
                    freight);
        }
    }
}

abstract class Customer {
    private int customerID;
    private String customerName;
    private String phonenumber;
    private String address;

    public Customer() {}

    public Customer(int customerID, String customerName, String phonenumber, String address) {
        this.customerID = customerID;
        this.customerName = customerName;
        this.phonenumber = phonenumber;
        this.address = address;
    }

    public int getCustomerID() { return customerID; }
    public String getName() { return customerName; }
    public String getPhonenumber() { return phonenumber; }
    public String getAddress() { return address; }

    public void setCustomerID(int customerID) { this.customerID = customerID; }
    public void setName(String name) { this.customerName = name; }
    public void setPhonenumber(String phonenumber) { this.phonenumber = phonenumber; }
    public void setAddress(String address) { this.address = address; }

    public abstract double applyDiscount(double amount);
}

class IndividualCustomer extends Customer {
    public IndividualCustomer(int customerID, String name, String phone, String address) {
        super(customerID, name, phone, address);
    }

    @Override
    public double applyDiscount(double amount) {
        return amount * 0.9;  // 个人用户9折
    }
}

class GroupCustomer extends Customer {
    public GroupCustomer(int customerID, String name, String phone, String address) {
        super(customerID, name, phone, address);
    }

    @Override
    public double applyDiscount(double amount) {
        return amount * 0.8;  // 集团用户8折
    }
}

class Product {
    private int number;
    private int productID;
    private String productName;
    private double weight;
    private double length;
    private double width;
    private double height;
    private FreightStrategy strategy;

    public Product(int number, int productID, String productName, double weight, double length, double width, double height) {
        this.number = number;
        this.productID = productID;
        this.productName = productName;
        this.weight = weight;
        this.length = length;
        this.width = width;
        this.height = height;
    }

    public void setCargoType(String type) {
        switch (type.toLowerCase()) {
            case "normal": strategy = new NormalStrategy(); break;
            case "expedite": strategy = new ExpediteStrategy(); break;  // 修正拼写错误
            case "dangerous": strategy = new DangerousCargoStrategy(); break;
            default: throw new IllegalArgumentException("无效货物类型");
        }
    }

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

    public double calculateFreight(double billingWeight) {
        return strategy.calculate(billingWeight);
    }

    public double getFreightRate(double billingWeight) {
        return strategy.getRate(billingWeight);
    }

    public int getNumber() { return number; }
    public String getProductName() { return productName; }
    public double getWeight() { return weight; }
    public double getLength() { return length; }
    public double getWidth() { return width; }
    public double getHeight() { return height; }
}

interface FreightStrategy {
    double calculate(double weight);
    double getRate(double weight);
}

class NormalStrategy implements FreightStrategy {
    @Override
    public double calculate(double weight) {
        return getRate(weight) * weight;
    }

    @Override
    public double getRate(double weight) {
        if (weight < 20) return 35;
        else if (weight < 50) return 30;
        else if (weight < 100) return 25;
        else return 15;
    }
}

class DangerousCargoStrategy implements FreightStrategy {
    @Override
    public double calculate(double weight) {
        return getRate(weight) * weight;
    }

    @Override
    public double getRate(double weight) {
        if (weight < 20) return 80;
        else if (weight < 50) return 50;
        else if (weight < 100) return 30;
        else return 20;
    }
}

class ExpediteStrategy implements FreightStrategy {  // 修正类名拼写
    @Override
    public double calculate(double weight) {
        return getRate(weight) * weight;
    }

    @Override
    public double getRate(double weight) {
        if (weight < 20) return 60;
        else if (weight < 50) return 50;
        else if (weight < 100) return 40;
        else return 30;
    }
}

class Flight {
    private String flightID;
    private String departureCity;
    private String arrivalCity;
    private String flightDate;
    private double maxLoadWeight;
    
    public Flight() {}
    
    public Flight(String flightID, String departureCity, String arrivalCity, String flightDate, double maxLoadWeight) {
        this.flightID = flightID;
        this.departureCity = departureCity;
        this.arrivalCity = arrivalCity;
        this.flightDate = flightDate;
        this.maxLoadWeight = maxLoadWeight;
    }
    
    public String getFlightID() { return flightID; }
    public String getDepartureCity() { return departureCity; }
    public String getArrivalCity() { return arrivalCity; }
    public String getFlightDate() { return flightDate; }
    public double getMaxLoadWeight() { return maxLoadWeight; }
}

class Order {
    private String orderID;
    private String orderDate;
    private String sendername;
    private String senderphonenumber;
    private String senderaddress;
    private String receivername;
    private String receiverphonenumber;
    private String receiveraddress;
    private Flight flightnumber;
    private PaymentMethod payment;
    
    public Order() {}
    
    public String getOrderID() { return orderID; }
    public void setOrderID(String orderID) { this.orderID = orderID; }

    public String getOrderDate() { return orderDate; }
    public void setOrderDate(String orderDate) { this.orderDate = orderDate; }

    public String getSendername() { return sendername; }
    public void setSendername(String sendername) { this.sendername = sendername; }

    public String getSenderphonenumber() { return senderphonenumber; }
    public void setSenderphonenumber(String senderphonenumber) {
        this.senderphonenumber = senderphonenumber;
    }

    public void setFlightnumber(Flight flightnumber) {
        this.flightnumber = flightnumber;
    }
    public Flight getFlightnumber() { return flightnumber; }

    public String getSenderaddress() { return senderaddress; }
    public void setSenderaddress(String senderaddress) { this.senderaddress = senderaddress; }

    public String getReceivername() { return receivername; }
    public void setReceivername(String receivername) { this.receivername = receivername; }

    public String getReceiverphonenumber() { return receiverphonenumber; }
    public void setReceiverphonenumber(String receiverphonenumber) { 
        this.receiverphonenumber = receiverphonenumber; 
    }

    public String getReceiveraddress() { return receiveraddress; }
    public void setReceiveraddress(String receiveraddress) { 
        this.receiveraddress = receiveraddress; 
    }

    public void setPayment(PaymentMethod method) {
        this.payment = method;
    }
    
    public PaymentMethod getPayment() {  // 新增getter方法
        return payment;
    }
    
    public void processPayment(double amount) {
        payment.pay(amount);
    }
}

interface PaymentMethod {
    void pay(double amount);
}

class WeChatPayment implements PaymentMethod {
    public void pay(double amount) {
        // 微信支付实现
    }
}

class AlipayPayment implements PaymentMethod {
    public void pay(double amount) {
        // 支付宝支付实现
    }
}

class CashPayment implements PaymentMethod {
    public void pay(double amount) {
        // 现金支付实现
    }
}

类图:

报表:

航空货运管理系统质量分析报告

一、核心问题定位

// Product.java
public void setCargoType(String type) {
    if (type.equals("DANGEROUS")) {
        if (weight > 50) {
            // 嵌套逻辑...
        } else if (...) {
            // 更多嵌套...
        }
    } 
    // 共4层嵌套...
}

🚨 严重问题

  • setCargoType方法:复杂度5(超标临界值4)
  • 嵌套深度达4层(建议≤3)
  • 包含12条语句(推荐≤10)

二、质量指标总览

文件 方法数 平均复杂度 分支覆盖率
Main8.java 2 3.0 1.7%
Product.java 11 1.36 18.4%

三、架构亮点

✅ 优秀实践

  • FreightStrategy.java:完美实现策略模式
  • 分支覆盖率30%(高于平均水平)
  • 支付模块轻松扩展现金支付方式

四、改进方案

🔧 重构建议

  1. 将Main8拆分为:
    • OrderService(订单处理)
    • PaymentProcessor(支付逻辑)
  2. 使用状态模式重构setCargoType方法
  3. 为复杂度>3的方法增加单元测试

三.踩坑与心得:

当运费计算变成"俄罗斯套娃"

// 初版的天真写法
public double calculateFreight() {
    if (type == "dangerous") {
        if (weight > 50) { 
            if (...) { /* 更多嵌套 */ } 
        }
    } // 后续还有7层...
}
在第三次调试时终于意识到问题——每次新增货物类型都要在这个方法里挖洞。后来用策略模式把计算规则拆分成独立类,终于让这个"套娃"解体了。

客户折扣的"身份危机"

旧方案

if (customerType.equals("VIP")) {
    // 折扣逻辑
} // 每次新增类型都要改这里

体会:当发现代码里总在用if-else区分不同类型时,就是该用继承和多态的信号了。

支付模块没搞出具体实现

// 初版交作业时的尴尬
class WeChatPayment {
    void pay(double amount) { 
        // 留空待实现...
    }
}

后续改进

  • 增加了支付日志记录
  • 实现真正的支付接口调用
  • 添加了支付异常处理

四.改进建议:

在开发这个航空货运系统的过程中,我发现代码质量有几个明显的提升空间。首先是方法拆分方面,很多方法都过于臃肿,比如运费计算方法里塞了太多条件判断,导致后期维护困难。建议把这些大方法拆分成小方法,每个方法只做一件事。比如可以把费率计算单独抽出来,重量校验也独立成方法,这样主方法就清爽多了。

代码中的嵌套层次太深也是个问题,特别是运费计算那里有好几层if-else嵌套,看着就头晕。建议用卫语句提前返回,或者把嵌套逻辑抽成独立方法。比如遇到非法参数直接返回,不要继续往下走。对于复杂的条件判断,可以考虑用策略模式或者工厂模式来替代,这样代码结构会更清晰。

注释方面目前做得还不够,特别是业务逻辑复杂的地方缺少必要的说明。建议在以下地方加注释:类头部说明这个类的职责,方法前说明业务逻辑和参数要求,复杂算法处加上实现思路。但要注意避免过度注释,好的代码应该自解释,只在必要的地方加注释。

异常处理可以做得更完善些。现在很多地方直接吞掉异常或者简单打印,建议定义业务异常类,在适当的地方捕获处理。比如重量为负数时应该抛出带明确提示的异常,而不是任由系统报错。支付失败也应该有专门的异常处理逻辑。

日志记录也需要加强,特别是在业务流程的关键节点。比如订单创建、运费计算、支付完成等重要操作都应该记录日志,方便后续排查问题。建议用日志级别区分重要性,比如debug日志记录详细流程,error日志记录异常情况。

代码重复问题也值得关注,比如各种校验逻辑散落在各处。建议把公共的校验逻辑抽成工具方法,比如参数非空检查、数值范围校验等。这样既避免重复,又保持校验标准统一。

对于经常变化的业务规则,比如运费费率、折扣策略等,建议设计成可配置的。可以把这些规则放到数据库或配置文件中,避免每次修改都要改代码。这样运营人员调整规则时就不需要开发介入。

最后提一下测试,目前单元测试覆盖不足。建议为每个业务方法编写测试用例,特别是边界条件要多测试。比如刚好卡在费率分界点的重量,最大最小的尺寸等。测试用例要随着代码一起维护,确保每次修改都不会破坏原有功能。

这些改进不用一次性全做完,可以分阶段逐步优化。每次修改一个小点,确保测试通过后再继续。保持代码整洁需要持续投入,但长远来看会大大降低维护成本。

五.总结:

✈️ 航空货运系统开发总结

🔧 技术实践收获

通过这次项目,深刻体会到策略模式对复杂业务规则的解耦能力。将运费计算从最初的多层if-else重构为策略模式后,新增货物类型再也不用修改核心代码,真正实现了"对扩展开放,对修改关闭"的原则。面向对象的继承特性也让客户折扣系统变得更加灵活。

📝 代码质量心得
  • 方法拆分:保持方法短小精悍(20行以内)大大提升了可读性
  • 减少嵌套:用卫语句替代深层嵌套,代码扁平化后调试更方便
  • 注释规范:在关键算法和业务规则处添加说明,三个月后回看依然清晰
🚀 后续优化方向
计划
  • 完善支付模块异常处理
  • 增加输入参数校验
  • 补充单元测试用例

💡 最重要体会:好的代码不是一蹴而就的,需要持续重构优化。每次提交都应该让代码比之前更整洁一点,这种渐进式改进才是可持续的开发方式。

posted on 2025-05-24 15:26  周婉辰  阅读(23)  评论(0)    收藏  举报