第二次Blog—航空货运管理系统

第二次Blog—航空货运管理系统
一、前言
本次题目集8-9中,围绕航空货运管理系统这一具体问题,遵守SRP(单一职责原则)、
OCP(开闭原则)、LSP(里氏代换原则)、DIP(依赖倒转原则)、CRP(合成复用原则)、LOD(迪米特法则)、ISP(接口隔离原则)。通过继承、多态等,实现代码迭代与更新。相比于第一周期题目集,本次题目集更加侧重于面向对象设计原则考察即类的设计而非运行逻辑设计。
二、设计与分析

1.类图分析部分
第八次题目集
499d204b-fcef-4610-a9ca-c8fbf5e346d9.pdf

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

interface RateStrategy {// 费率策略接口,方便后续费率计算拓展
    double calculateRate(double weight);
}
// 具体的费率策略实现类
class RealRateStrategy implements RateStrategy {
    @Override
    public double calculateRate(double weight) {
        if (weight < 20) {//分层不同费率
            return 35;
        } else if (weight < 50) {
            return 30;
        } else if (weight < 100) {
            return 25;
        } else {
            return 15;
        }
    }
}
// 支付抽象类方便后续拓展
abstract class Payment {
    public abstract void pay(double amount);
}
// 微信支付类
class WechatPayment extends Payment {
    @Override//只需要输出是什么支付就行了
    public void pay(double amount) {
        System.out.println("使用微信支付,支付金额:" + amount);
    }
}
class Alipayment extends Payment {// 支付宝支付类
    @Override
    public void pay(double amount) {
        System.out.println("使用支付宝支付,支付金额:" + amount);
    }
}
// 单个货物信息类
class GoodsItem {
    private int goodsId;
    private String goodsName;
    private int width;
    private int length;
    private int height;
    private double weight;
    private double volumeWeight;
    private double chargeWeight;
    private double rate;
    private double amount;
    private RateStrategy rateStrategy;
    // 简单无参构造
    public GoodsItem() {
        this(0, "", 0, 0, 0, 0.0, new RealRateStrategy());
    }
    // 有参构造
    public GoodsItem(int goodsId, String goodsName, int width, int length, int height, double weight, RateStrategy rateStrategy) {
        this.goodsId = goodsId;
        this.goodsName = goodsName;
        this.width = width;
        this.length = length;
        this.height = height;
        this.weight = weight;
        this.rateStrategy = rateStrategy;
        calculateVolumeWeight();
       
        calculateChargeWeight();
        calculateRate();
        calculateAmount();
    }
    // 计算体积重量
    private void calculateVolumeWeight() {
        
        volumeWeight = (width * length * height) / 6000;
        //System.out.printf("%d %d %d\n",width,length,height);
      //  System.out.printf("%.2f\n",volumeWeight);
    }
    // 计算计费重量(anguize选大的)
    private void calculateChargeWeight() {
        chargeWeight = Math.max(weight, volumeWeight);
       // System.out.printf("%.2f\n",chargeWeight);
    }
    // 计算费率
    private void calculateRate() {
        rate = rateStrategy.calculateRate(chargeWeight);
    }
    // 计算运费
    private void calculateAmount() {
        amount = chargeWeight * rate;
    }

    // Getter & Setter实现
    public int getGoodsId() {
        return goodsId;
    }

    public void setGoodsId(int goodsId) {
        this.goodsId = goodsId;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }
    public int getWidth() {
        return width;
    }
    public void setWidth(int width) {
        this.width = width;
    }
    public int getLength() {
        return length;
    }
    public void setLength(int length) {
        this.length = length;
    }
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
    public double getWeight() {
        return weight;
    }
    public void setWeight(double weight) {
        this.weight = weight;
    }
    public double getVolumeWeight() {
        return volumeWeight;
    }
    public double getChargeWeight() {
        return chargeWeight;
    }
    public double getRate() {
        return rate;
    }

    public double getAmount() {
        return amount;
    }
    public RateStrategy getRateStrategy() {
        return rateStrategy;
    }
    public void setRateStrategy(RateStrategy rateStrategy) {
        this.rateStrategy = rateStrategy;
    }
}
// 订单详情类
class OrderDetails {//详细的订单输出内容(仿照超市购物类
    private Order order;
    private GoodsItem goodsItem;
    public OrderDetails(Order order, GoodsItem goodsItem) {
        this.order = order;
        this.goodsItem = goodsItem;
    }

    public Order getOrder() {
        return order;
    }

    public GoodsItem getGoodsItem() {
        return goodsItem;
    }
}
// 订单类
class Order {//链表类方便后续订单可能操作
    private int orderId;
    private String orderDate;
    private String senderAddress;//简单构造私有对象,因为没有第三方了
    private String senderName;
    private String senderPhone;
    private String recipientName;
    private String recipientAddress;
    private String recipientPhone;
    private LinkedList<GoodsItem> goodsList;//链表方便或许功能增加
    private double totalWeight;
    private double totalAmount;
    // 无参构造
    public Order() {
        this(0,"","","","","","","",new LinkedList<GoodsItem>() );
    }
    // 有参构造
    public Order(int orderId, String orderDate, String senderAddress, String senderName, String senderPhone, String recipientName,String recipientAddress,String recipientPhone, LinkedList<GoodsItem> goodsList) {
        this.orderId = orderId;
        this.orderDate = orderDate;
        this.senderAddress = senderAddress;
        this.senderName = senderName;
        this.senderPhone = senderPhone;
        this.recipientName = recipientName;
        this.recipientAddress = recipientAddress;
        this.recipientPhone = recipientPhone;
        this.goodsList = goodsList;
        calculateTotalWeight();//最终的订单重量
        calculateTotalAmount();
    }
    // 计算订单总重量
    private void calculateTotalWeight() {
        totalWeight = 0;
        for (GoodsItem item : goodsList) {//仿照超市购物类
            totalWeight += item.getChargeWeight();
        }
    }
    // 计算订单总运费
    private void calculateTotalAmount() {
        totalAmount = 0;
        for (GoodsItem item : goodsList) {
            totalAmount += item.getAmount();
        }
    }
    // Getter & Setter方法实现
    public int getOrderId() {
        return orderId;
    }
    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }
    public String getOrderDate() {
        return orderDate;
    }
    public void setOrderDate(String orderDate) {
        this.orderDate = orderDate;
    }
    public String getSenderAddress() {
        return senderAddress;
    }
    public void setSenderAddress(String senderAddress) {
        this.senderAddress = senderAddress;
    }

    public String getSenderName() {
        return senderName;
    }

    public void setSenderName(String senderName) {
        this.senderName = senderName;
    }
    public String getSenderPhone() {
        return senderPhone;
    }

    public void setSenderPhone(String senderPhone) {
        this.senderPhone = senderPhone;
    }

    public String getRecipientName() {
        return recipientName;
    }

    public void setRecipientName(String recipientName) {
        this.recipientName = recipientName;
    }

    public String getRecipientAddress() {
        return recipientAddress;
    }
    public void setRecipientAddress(String recipientAddress) {
        this.recipientAddress = recipientAddress;
    }

    public String getRecipientPhone() {
        return recipientPhone;
    }

    public void setRecipientPhone(String recipientPhone) {
        this.recipientPhone = recipientPhone;
    }

    public LinkedList<GoodsItem> getGoodsList() {
        return goodsList;
    }
    public void setGoodsList(LinkedList<GoodsItem> goodsList) {
        this.goodsList = goodsList;
        calculateTotalWeight();
        calculateTotalAmount();
    }
    public double getTotalWeight() {
        return totalWeight;
    }
    public double getTotalAmount() {
        return totalAmount;
    }
}

// 顾客类
class Customer {
    private int customerId;
    private String customerName;
    private String customerPhone;
    private String customerAddress;
    // 无参构造
    public Customer() {
        this(0, "", "", "");
    }
    // 有参构造
    public Customer(int customerId, String customerName, String customerPhone, String customerAddress) {
        this.customerId = customerId;
        this.customerName = customerName;
        this.customerPhone = customerPhone;
        this.customerAddress = customerAddress;
    }

    // Getter & Setter
    public int getCustomerId() {
        return customerId;
    }

    public void setCustomerId(int customerId) {
        this.customerId = customerId;
    }

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public String getCustomerPhone() {
        return customerPhone;
    }

    public void setCustomerPhone(String customerPhone) {
        this.customerPhone = customerPhone;
    }

    public String getCustomerAddress() {
        return customerAddress;
    }

    public void setCustomerAddress(String customerAddress) {
        this.customerAddress = customerAddress;
    }
}

// 航班类
class Flight {
    private String flightNumber;
    private String departureAirport;
    private String arrivalAirport;
    private String flightDate;
    private double maxLoadCapacity;
    public Flight(String flightNumber, String departureAirport, String arrivalAirport, String flightDate, double maxLoadCapacity) {
        this.flightNumber = flightNumber;
        this.departureAirport = departureAirport;
        this.arrivalAirport = arrivalAirport;
        this.flightDate = flightDate;
        this.maxLoadCapacity = maxLoadCapacity;
    }

    // Getter & Setter方法实现
    public String getFlightNumber() {
        return flightNumber;
    }

    public void setFlightNumber(String flightNumber) {
        this.flightNumber = flightNumber;
    }

    public String getDepartureAirport() {
        return departureAirport;
    }

    public void setDepartureAirport(String departureAirport) {
        this.departureAirport = departureAirport;
    }

    public String getArrivalAirport() {
        return arrivalAirport;
    }

    public void setArrivalAirport(String arrivalAirport) {
        this.arrivalAirport = arrivalAirport;
    }

    public String getFlightDate() {
        return flightDate;
    }

    public void setFlightDate(String flightDate) {
        this.flightDate = flightDate;
    }

    public double getMaxLoadCapacity() {
        return maxLoadCapacity;
    }

    public void setMaxLoadCapacity(double maxLoadCapacity) {
        this.maxLoadCapacity = maxLoadCapacity;
    }
}

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

//简单读取信息然后直接创建对象
        // 读取客户信息
        int customerId = scanner.nextInt();
        scanner.nextLine();
        String customerName = scanner.nextLine();
        String customerPhone = scanner.nextLine();
        String customerAddress = scanner.nextLine();
        Customer customer = new Customer(customerId, customerName, customerPhone, customerAddress);

        // 读取货物信息
        int goodsCount = scanner.nextInt();
        LinkedList<GoodsItem> goodsList = new LinkedList<>();
        for (int i = 0; i < goodsCount; i++) {
            int goodsId = scanner.nextInt();
            scanner.nextLine();
            String goodsName = scanner.nextLine();
            int width = scanner.nextInt();
            int length = scanner.nextInt();
            int height = scanner.nextInt();
            double weight = scanner.nextDouble();
            GoodsItem goodsItem = new GoodsItem(goodsId, goodsName, width, length, height, weight, new RealRateStrategy());
            goodsList.add(goodsItem);
        }

        // 读取航班信息
        String flightNumber = scanner.next();
        scanner.nextLine();
        String departureAirport = scanner.nextLine();
        String arrivalAirport = scanner.nextLine();
        String flightDate = scanner.nextLine();
        double maxLoadCapacity = scanner.nextDouble();
        Flight flight = new Flight(flightNumber, departureAirport, arrivalAirport, flightDate, maxLoadCapacity);
        // 读取订单信息
        int orderId = scanner.nextInt();
        scanner.nextLine();
        String orderDate = scanner.nextLine();
        String senderAddress = scanner.nextLine();
        String senderName = scanner.nextLine();
        String senderPhone = scanner.nextLine();
        String recipientAddress = scanner.nextLine();
        String recipientName = scanner.nextLine();
        String recipientPhone = scanner.nextLine();
        Order order = new Order(orderId, orderDate, senderAddress, senderName, senderPhone, recipientName, recipientAddress, recipientPhone, goodsList);

        // 通过调用方法直接输出
        if (order.getTotalWeight() > flight.getMaxLoadCapacity()) {
            System.out.println("The flight with flight number:" + flight.getFlightNumber() + " has exceeded its load capacity and cannot carry the order.");
        } else {
            System.out.println("客户:" + customer.getCustomerName() + "(" + customer.getCustomerPhone() + ")订单信息如下:");
            System.out.println("-----------------------------------------");
            System.out.println("航班号:" + flight.getFlightNumber());
            System.out.println("订单号:" + order.getOrderId());
            System.out.println("订单日期:" + order.getOrderDate());
            System.out.println("发件人姓名:" + order.getSenderName());
            System.out.println("发件人电话:" + order.getSenderPhone());
            System.out.println("发件人地址:" + order.getSenderAddress());
            System.out.println("收件人姓名:" + order.getRecipientName());
            System.out.println("收件人电话:" + order.getRecipientPhone());
            System.out.println("收件人地址:" + order.getRecipientAddress());
            System.out.printf("订单总重量(kg):%.1f\n", order.getTotalWeight());
            System.out.printf("微信支付金额:%.1f\n", order.getTotalAmount());
            System.out.println("\n货物明细如下:");
            System.out.println("-----------------------------------------");
            System.out.println("明细编号\t货物名称\t计费重量\t计费费率\t应交运费");
            int index = 1;
            for (GoodsItem item : order.getGoodsList()) {
                System.out.printf("%d\t%s\t%.1f\t%.1f\t%.1f\n", index++, item.getGoodsName(), item.getChargeWeight(), item.getRate(), item.getAmount());
            }
        }

        scanner.close();
    }
}

类图

类图分析:

一、类与方法清单

  1. 策略模式相关
    类/接口 //方法
    RateStrategy double calculateRate(double weight) 费率计算策略接口(核心抽象)
    RealRateStrategy @Override calculateRate() 实现分层费率逻辑
    Payment abstract void pay(double amount) 支付方式抽象类
    WechatPayment @Override pay() 输出微信支付信息
    Alipayment @Override pay() 输出支付宝支付信息
  2. 核心业务类
    类 主要属性 主要方法
    GoodsItem goodsId,

goodsName, width/length/height, weight, volumeWeight, chargeWeight, rate, amount

calculateVolumeWeight()(体积重量计算)
calculateChargeWeight()(计费重量取大值)
calculateRate()(调用策略)
calculateAmount()(运费计算)

Order orderId,
orderDate, 发件人/收件人信息, goodsList, totalWeight, totalAmount calculateTotalWeight()(总重量累加)
calculateTotalAmount()(总金额累加)

Customer
customerId, name, phone, address 仅包含Getter/Setter
Flight flightNumber, departure/arrivalAirport, flightDate, maxLoadCapacity 仅包含Getter/Setter
OrderDetails Order order, GoodsItem goodsItem 组合订单与货物项

Main 程序入口,处理输入数据,创建对象(Customer/Order/Flight),输出订单和运费信息
二、类关系分析

  1. 依赖关系
    Main 依赖以下类:
    Customer(创建客户对象)
    Order(创建订单对象)
    Flight(创建航班对象)
    GoodsItem(构建货物列表)
    GoodsItem 依赖:
    RateStrategy(通过接口调用费率计算策略)

  2. 组合关系
    GoodsItem 组合 RateStrategy

  3. 聚合关系
    Order 聚合多个 GoodsItem,订单通过goodsList管理多个货物项,但货物项可以独立存在

  4. 继承关系
    支付类继承关系:
    子类必须实现pay()方法

  5. 策略模式(Strategy Pattern)

策略接口:RateStrategy

具体策略:RealRateStrategy

第九次题目集
b9cec79b-8012-4901-843e-3d48f27d28a6.pdf

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

interface RateStrategy {// 费率策略接口,方便后续费率计算拓展
    double calculateRate(double weight);
}
// 具体的费率策略实现类
//危险货物费率策略
class DangerousRateStrategy implements RateStrategy {
    @Override
    public double calculateRate(double weight) {
        if (weight < 20) {//分层不同费率
            return 80;
        } else if (weight < 50) {
            return 50;
        } else if (weight < 100) {
            return 30;
        } else {
            return 20;
        }
    }
}
//加急货物费率策略
class ExpediteRateStrategy implements RateStrategy {
    @Override
    public double calculateRate(double weight) {
        if (weight < 20) {//分层不同费率
            return 60;
        } else if (weight < 50) {
            return 50;
        } else if (weight < 100) {
            return 40;
        } else {
            return 30;
        }
    }
}
//普通货物费率策略
class NormalRateStrategy implements RateStrategy {
    @Override
    public double calculateRate(double weight) {
        if (weight < 20) {//分层不同费率
            return 35;
        } else if (weight < 50) {
            return 30;
        } else if (weight < 100) {
            return 25;
        } else {
            return 15;
        }
    }
}
// 支付抽象类方便后续拓展
abstract class Payment {
    public abstract void pay(double amount);
}
// 微信支付类
class WechatPayment extends Payment {
    @Override//只需要输出是什么支付就行了
    public void pay(double amount) {
        System.out.println("微信支付金额:" + amount);
    }
}
class Alipayment extends Payment {// 支付宝支付类
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付金额:" + amount);
    }
}
class CashPayment extends Payment {// 现金支付类
    @Override
    public void pay(double amount) {
        System.out.println("现金支付金额:" + amount);
    }
}
abstract class GoodsItem {// 货物项抽象类
    // 货物基础信息
    protected int goodsId;
    protected String goodsName;
    protected int width, length, height; // 尺寸(厘米)
    protected double weight; // 实际重量(kg)
    protected double volumeWeight; // 体积重量(kg = 长*宽*高/6000)
    protected double chargeWeight; // 计费重量(取实际重量和体积重量的较大值)
    protected double rate; // 计费费率(元/kg)
    protected double amount; // 单项运费(计费重量*费率)
    protected RateStrategy rateStrategy; // 费率策略对象
 // 构造方法:初始化货物信息并计算各项费用
    public GoodsItem(int goodsId, String goodsName, int width, int length, int height, double weight, RateStrategy rateStrategy) {
        this.goodsId = goodsId;
        this.goodsName = goodsName;
        this.width = width;
        this.length = length;
        this.height = height;
        this.weight = weight;
        this.rateStrategy = rateStrategy;
        calculateVolumeWeight(); // 计算体积重量
        calculateChargeWeight(); // 确定计费重量
        calculateRate(); // 根据策略计算费率
        calculateAmount(); // 计算单项运费
    }

    private void calculateVolumeWeight() {    // 计算体积重量(内部方法)
        volumeWeight = (width * length * height) / 6000.0;
    }

    private void calculateChargeWeight() {    // 计算计费重量(内部方法)
        chargeWeight = Math.max(weight, volumeWeight);
    }

    private void calculateRate() {
        rate = rateStrategy.calculateRate(chargeWeight);
    }
    private void calculateAmount() {
        amount = chargeWeight * rate;
    }

    // Getter & Setter
    public int getGoodsId() {
        return goodsId;
    }
    public String getGoodsName() {
        return goodsName;
    }
    public double getChargeWeight() {
        return chargeWeight;
    }
    public double getRate() {
        return rate;
    }
    public double getAmount() {
        return amount;
    }
}

class DangerousGoodsItem extends GoodsItem {// 危险货物具体类(自动关联危险货物费率策略)
    public DangerousGoodsItem(int goodsId, String goodsName, int width, int length, int height, double weight) {
        super(goodsId, goodsName, width, length, height, weight, new DangerousRateStrategy());
    }
}
// 加急货物具体类(自动关联加急货物费率策略)
class ExpediteGoodsItem extends GoodsItem {
    public ExpediteGoodsItem(int goodsId, String goodsName, int width, int length, int height, double weight) {
        super(goodsId, goodsName, width, length, height, weight, new ExpediteRateStrategy());
    }
}
class NormalGoodsItem extends GoodsItem {
// 普通货物具体类(自动关联普通货物费率策略)
    public NormalGoodsItem(int goodsId, String goodsName, int width, int length, int height, double weight) {
        super(goodsId, goodsName, width, length, height, weight, new NormalRateStrategy());
    }
}
// 订单详情类
class OrderDetails {//详细的订单输出内容(仿照超市购物类
    private Order order;
    private GoodsItem goodsItem;
    public OrderDetails(Order order, GoodsItem goodsItem) {
        this.order = order;
        this.goodsItem = goodsItem;
    }

    public Order getOrder() {
        return order;
    }

    public GoodsItem getGoodsItem() {
        return goodsItem;
    }
}
// 订单类
class Order {//链表类方便后续订单可能操作
    private int orderId;
    private String orderDate;
    private String senderAddress;//简单构造私有对象,因为没有第三方了
    private String senderName;
    private String senderPhone;
    private String recipientName;
    private String recipientAddress;
    private String recipientPhone;
    private LinkedList<GoodsItem> goodsList;//链表方便或许功能增加
    private double totalWeight; // 订单总计费重量
    private double totalAmount; // 订单总费用(含客户折扣)
    private Customer customer; // 关联客户对象(用于获取折扣)
    // 无参构造
    public Order() {
        this(0,"","","","","","","",new LinkedList<GoodsItem>() ,null);
    }
    // 有参构造
    public Order(int orderId, String orderDate, String senderAddress, String senderName, String senderPhone, String recipientName,String recipientAddress,String recipientPhone, LinkedList<GoodsItem> goodsList ,Customer customer) {
        this.orderId = orderId;
        this.orderDate = orderDate;
        this.senderAddress = senderAddress;
        this.senderName = senderName;
        this.senderPhone = senderPhone;
        this.recipientName = recipientName;
        this.recipientAddress = recipientAddress;
        this.recipientPhone = recipientPhone;
        this.goodsList = goodsList;
        this.customer = customer;
        calculateTotalWeight();//最终的订单重量
        calculateTotalAmount();
    }
    // 计算订单总重量
    private void calculateTotalWeight() {
        totalWeight = 0;
        for (GoodsItem item : goodsList) {//仿照超市购物类
            totalWeight += item.getChargeWeight();
        }
    }
    // 计算订单总运费
    private void calculateTotalAmount() {
        totalAmount = 0;
        for (GoodsItem item : goodsList) {
            totalAmount += item.getAmount();
        }
        totalAmount *= customer.getDiscountRate();
    }
    // Getter & Setter方法实现
    public int getOrderId() {
        return orderId;
    }
    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }
    
    public String getOrderDate() {
        return orderDate;
    }
    public void setOrderDate(String orderDate) {
        this.orderDate = orderDate;
    }
    public String getSenderAddress() {
        return senderAddress;
    }
    public void setSenderAddress(String senderAddress) {
        this.senderAddress = senderAddress;
    }

    public String getSenderName() {
        return senderName;
    }

    public void setSenderName(String senderName) {
        this.senderName = senderName;
    }
    public String getSenderPhone() {
        return senderPhone;
    }

    public void setSenderPhone(String senderPhone) {
        this.senderPhone = senderPhone;
    }

    public String getRecipientName() {
        return recipientName;
    }

    public void setRecipientName(String recipientName) {
        this.recipientName = recipientName;
    }

    public String getRecipientAddress() {
        return recipientAddress;
    }
    public void setRecipientAddress(String recipientAddress) {
        this.recipientAddress = recipientAddress;
    }

    public String getRecipientPhone() {
        return recipientPhone;
    }

    public void setRecipientPhone(String recipientPhone) {
        this.recipientPhone = recipientPhone;
    }

    public LinkedList<GoodsItem> getGoodsList() {
        return goodsList;
    }
    public void setGoodsList(LinkedList<GoodsItem> goodsList) {
        this.goodsList = goodsList;
        calculateTotalWeight();
        calculateTotalAmount();
    }
    public double getTotalWeight() {
        return totalWeight;
    }
    public double getTotalAmount() {
        return totalAmount;
    }
}
abstract class Customer {
// 客户抽象类(包含折扣策略)
    protected int customerId;
    protected String customerName;
    protected String customerPhone;
    protected String customerAddress;

    public Customer(int customerId, String customerName, String customerPhone, String customerAddress) {
        this.customerId = customerId;
        this.customerName = customerName;
        this.customerPhone = customerPhone;
        this.customerAddress = customerAddress;
    }

    public abstract double getDiscountRate();// 子类实现折扣率(个人0.9/企业0.8)
    // Getter & Setter
    public int getCustomerId() {
        return customerId;
    }
    public void setCustomerId(int customerId) {
        this.customerId = customerId;
    }
    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public String getCustomerPhone() {
        return customerPhone;
    }

    public void setCustomerPhone(String customerPhone) {
        this.customerPhone = customerPhone;
    }

    public String getCustomerAddress() {
        return customerAddress;
    }

    public void setCustomerAddress(String customerAddress) {
        this.customerAddress = customerAddress;
    }
}
class IndividualCustomer extends Customer {// 个人客户(享受9折优惠)
    public IndividualCustomer(int customerId, String customerName, String customerPhone, String customerAddress) {
        super(customerId, customerName, customerPhone, customerAddress);
    }

    @Override
    public double getDiscountRate() {
        return 0.9; // 个人客户享受9折优惠
    }
}
class CorporateCustomer extends Customer {// 企业客户(享受8折优惠)
    public CorporateCustomer(int customerId, String customerName, String customerPhone, String customerAddress) {
        super(customerId, customerName, customerPhone, customerAddress);
    }

    @Override
    public double getDiscountRate() {
        return 0.8; // 企业客户享受8折优惠
    }
}

// 航班类
class Flight {
    private String flightNumber;
    private String departureAirport;
    private String arrivalAirport;
    private String flightDate;
    private double maxLoadCapacity;
    public Flight(String flightNumber, String departureAirport, String arrivalAirport, String flightDate, double maxLoadCapacity) {
        this.flightNumber = flightNumber;
        this.departureAirport = departureAirport;
        this.arrivalAirport = arrivalAirport;
        this.flightDate = flightDate;
        this.maxLoadCapacity = maxLoadCapacity;
    }

    // Getter & Setter方法实现
    public String getFlightNumber() {
        return flightNumber;
    }

    public void setFlightNumber(String flightNumber) {
        this.flightNumber = flightNumber;
    }

    public String getDepartureAirport() {
        return departureAirport;
    }

    public void setDepartureAirport(String departureAirport) {
        this.departureAirport = departureAirport;
    }

    public String getArrivalAirport() {
        return arrivalAirport;
    }

    public void setArrivalAirport(String arrivalAirport) {
        this.arrivalAirport = arrivalAirport;
    }

    public String getFlightDate() {
        return flightDate;
    }

    public void setFlightDate(String flightDate) {
        this.flightDate = flightDate;
    }

    public double getMaxLoadCapacity() {
        return maxLoadCapacity;
    }

    public void setMaxLoadCapacity(double maxLoadCapacity) {
        this.maxLoadCapacity = maxLoadCapacity;
    }
}
//主类
class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取客户信息
        String customerType = scanner.nextLine();
        Customer customer;
        int customerId;
        String customerName, customerPhone, customerAddress;
        if (customerType.equals("Individual")) {
            customerId = scanner.nextInt();
            scanner.nextLine(); // 消费换行符
            customerName = scanner.nextLine();
            customerPhone = scanner.nextLine();
            customerAddress = scanner.nextLine();
            customer = new IndividualCustomer(customerId, customerName, customerPhone, customerAddress);
        } else {
            customerId = scanner.nextInt();
            scanner.nextLine(); // 消费换行符
            customerName = scanner.nextLine();
            customerPhone = scanner.nextLine();
            customerAddress = scanner.nextLine();
            customer = new CorporateCustomer(customerId, customerName, customerPhone, customerAddress);
        }

        // 读取货物信息
        String goodsItemType = scanner.nextLine();
        int goodsCount = scanner.nextInt();
        LinkedList<GoodsItem> goodsList = new LinkedList<>();
        for (int i = 0; i < goodsCount; i++) {
            int goodsId = scanner.nextInt();
            scanner.nextLine(); // 消费换行符
            String goodsName = scanner.nextLine();
            int width = scanner.nextInt();
            int length = scanner.nextInt();
            int height = scanner.nextInt();
            double weight = scanner.nextDouble();
            GoodsItem goodsItem;
            if (goodsItemType.equals("Dangerous")) {
                goodsItem = new DangerousGoodsItem(goodsId, goodsName, width, length, height, weight);
            } else if (goodsItemType.equals("Expedite")) {
                goodsItem = new ExpediteGoodsItem(goodsId, goodsName, width, length, height, weight);
            } else {
                goodsItem = new NormalGoodsItem(goodsId, goodsName, width, length, height, weight);
            }
            goodsList.add(goodsItem);
        }

        // 读取航班信息
        String flightNumber = scanner.next();
        scanner.nextLine(); // 消费换行符
        String departureAirport = scanner.nextLine();
        String arrivalAirport = scanner.nextLine();
        String flightDate = scanner.nextLine();
        double maxLoadCapacity = scanner.nextDouble();
        Flight flight = new Flight(flightNumber, departureAirport, arrivalAirport, flightDate, maxLoadCapacity);

        // 读取订单信息
        int orderId = scanner.nextInt();
        scanner.nextLine(); // 消费换行符
        String orderDate = scanner.nextLine();
        String senderAddress = scanner.nextLine();
        String senderName = scanner.nextLine();
        String senderPhone = scanner.nextLine();
        String recipientAddress = scanner.nextLine();
        String recipientName = scanner.nextLine();
        String recipientPhone = scanner.nextLine();
        Order order = new Order(orderId, orderDate, senderAddress, senderName, senderPhone, recipientName, recipientAddress, recipientPhone, goodsList, customer);

        // 读取支付方式
        String payment = scanner.nextLine();
        Payment paymentMethod;
        if (payment.equals("Wechat")) {
            paymentMethod = new WechatPayment();
        } else if (payment.equals("ALiPay")) {
            paymentMethod = new Alipayment();
        } else {
            paymentMethod = new CashPayment();
        }

        // 输出处理
        if (order.getTotalWeight() > flight.getMaxLoadCapacity()) {
            System.out.println("The flight with flight number:" + flight.getFlightNumber() + " has exceeded its load capacity and cannot carry the order.");
        } else {
            System.out.println("客户:" + customer.getCustomerName() + "(" + customer.getCustomerPhone() + ")订单信息如下:");
            System.out.println("-----------------------------------------");
            System.out.println("航班号:" + flight.getFlightNumber());
            System.out.println("订单号:" + order.getOrderId());
            System.out.println("订单日期:" + order.getOrderDate());
            System.out.println("发件人姓名:" + order.getSenderName());
            System.out.println("发件人电话:" + order.getSenderPhone());
            System.out.println("发件人地址:" + order.getSenderAddress());
            System.out.println("收件人姓名:" + order.getRecipientName());
            System.out.println("收件人电话:" + order.getRecipientPhone());
            System.out.println("收件人地址:" + order.getRecipientAddress());
            System.out.printf("订单总重量(kg):%.1f\n", order.getTotalWeight());
            
            // 支付方式输出
            String paymentType;
            if (payment.equals("Wechat")) {
                paymentType = "微信";
            } else if (payment.equals("ALiPay")) {
                paymentType = "支付宝";
            } else {
                paymentType = "现金";
            }
            System.out.printf("%s支付金额:%.1f\n", paymentType, order.getTotalAmount());
            
            System.out.println("\n货物明细如下:");
            System.out.println("-----------------------------------------");
            System.out.println("明细编号\t货物名称\t计费重量\t计费费率\t应交运费");
            int index = 1;
            for (GoodsItem item : order.getGoodsList()) {
                System.out.printf("%d\t%s\t%.1f\t%.1f\t%.1f\n", index++, item.getGoodsName(), item.getChargeWeight(), item.getRate(), item.getAmount());
            }
        }
        scanner.close();
    }
}
类图:



分析:类/接口 方法 说明
RateStrategy double calculateRate(double weight) 费率策略接口(核心抽象)
DangerousRateStrategy @Override calculateRate() 危险货物费率
ExpediteRateStrategy @Override calculateRate() 加急货物费率
NormalRateStrategy @Override calculateRate() 普通货物费率
(Payment abstract void pay(double amount) 支付方式抽象类
WechatPayment @Override pay() 输出微信支付信息
Alipayment @Override pay() 输出支付宝支付信息
CashPayment @Override pay() 新增现金支付方式

GoodsItem (抽象)
goodsId, goodsName, 尺寸, weight, volumeWeight, chargeWeight, rate, amount 新增抽象类,公共属性与方法集中管理

Order 新增Customer customer,总金额计算时应用折扣(totalAmount *= discount)支持客户分级折扣
Customer (抽象) 新增抽象方法getDiscountRate() 客户类型策略化
IndividualCustomer @Override getDiscountRate()返回0.9 个人客户9折
CorporateCustomer @Override getDiscountRate()返回0.8 企业客户8折
2.SourceMonitor图分析
第八题:


Lines:代码总行数为 474 行
Statements:语句数为 25 条 ,语句数量较少。
Percent Branch Statements:分支语句比例为 16.0% ,说明代码中存在一定比例的条件判断和循环等逻辑,相较于一般简单代码略高。
Method Call Statements:方法调用语句数为 8 条 ,方法间的调用操作不是特别频繁。
Percent Lines with Comments:注释行比例仅 1.3% ,注释严重不足,极大影响代码可读性和可维护性。
Classes and Interfaces:类和接口总数为 11 个
Methods per Class:每个类平均方法数为 5.00 ,说明类中方法数量分布相对均衡,职责单一。
代码复杂度指标
Line Number of Deepest Block:最深代码块行数为 12 行 ,存在一定深度的代码块,但相对来说不算过深。
Maximum Block Depth:最大代码块深度为 3 ,逻辑嵌套层次不是特别多。
Average Block Depth:平均代码块深度为 1.36 ,代码块嵌套深度较浅。
结合代码的综合分析
设计原则方面
单一职责原则:部分类存在职责不够单一的问题。例如GoodsItem类既负责货物信息的存储,又承担了体积重量、计费重量、费率、运费等计算逻辑
开闭原则:在费率策略方面,通过接口RateStrategy及其实现类RealRateStrategy ,有一定的扩展性,符合开闭原则。依赖倒置原则:代码中存在一定的依赖倒置问题。比如GoodsItem类直接依赖具体的RealRateStrategy实现类,而非依赖更抽象的RateStrategy接口,导致耦合度相对较高
代码质量方面
注释缺失:如文本数据指标中注释行比例极低,代码中除了接口和类的简单功能说明外,核心业务逻辑(如各种费用计算方法)缺少注释,对代码理解和维护造成极大困难。
硬编码问题:在RealRateStrategy类中,费率数值(35、30、25、15 )是硬编码形式,不利于后期修改和维护,若业务规则变更,需多处修改代码,比如迭代时就需要改动很多
重复代码:多个类中构造函数存在重复代码,如Customer、Order等类的无参构造函数只是简单调用有参构造函数,后续需要优化
雷达图(Kiviat Graph):从图表看,各项指标分布中,注释比例极低,对应代码中实际注释严重不足的问题
柱状图(Block Histogram):柱状图显示大部分语句集中在嵌套深度较低区域(0 - 4 ),这逻辑嵌套层次相对较浅

第九题:


代码指标
行数(Lines):533 ,代码规模适中。
语句数(Statements):241 ,语句不算少,若分布不合理可能影响可读性。
分支语句比例(Percent Branch Statements):10.8% ,分支逻辑占比不算高,代码逻辑结构相对简单。
方法调用语句数(Method Call Statements):16 ,方法调用不算频繁。
注释行比例(Percent Lines with Comments):11.1% ,注释量较少,不利于他人理解代码逻辑。
类和接口数(Classes and Interfaces):13 ,类型定义较多,职责划分合理化。
图表情况
雷达图(Kiviat Graph):各项指标分布若不均匀,说明代码在某些方面表现不佳。比如若 “% Comments” 指标偏低,结合文本信息中注释行比例低,代码可读性差
柱状图(Block Histogram):大部分语句集中在嵌套深度较低区域(0 - 4 ),代码逻辑嵌套不深,相对易读易懂。
代码块深度相关
最深代码块行数(Line Number of Deepest Block):426 行 ,单个深度代码块行数较多,可能存在长方法或复杂嵌套逻辑。
最大代码块深度(Maximum Block Depth):5 ,说明代码中存在一定深度的逻辑嵌套。
平均代码块深度(Average Block Depth):1.74 ,整体代码块嵌套深度平均值不算高。
3.两次代码中七个面向对象设计原则的具体体现:
1.单一职责原则(SRP)
第一次代码:
GoodsItem 类同时负责货物数据存储和运费计算,职责较为集中。
Order 类管理订单信息并计算总重量和金额,存在一定耦合。

第二次代码优化:
将 客户折扣逻辑 分离到 Customer 子类(如 CorporateCustomer),职责更清晰。
GoodsItem 改为抽象类,子类(如 DangerousGoodsItem)通过继承绑定具体策略,分解计算职责。
结论:
第二次代码通过继承和策略模式,更严格遵循 SRP。
2.开闭原则(OCP)
第一次代码:
支持通过 RateStrategy 接口扩展新费率策略,但对客户类型和支付方式的扩展需要修改代码。
第二次代码优化:
新增客户类型(如企业客户)、货物类型(如危险品)、支付方式(如现金)时,只需扩展子类或实现接口,无需修改已有代码,这就是第一次代码类设计中开闭原则的体现,使得代码可维护性可扩展性良好
3. 里氏替换原则(LSP)
两次代码均有:
Payment 的子类(如 WechatPayment)完全实现父类抽象方法,可无缝替换。
GoodsItem 子类(如 ExpediteGoodsItem)继承父类行为并绑定策略,不破坏原有逻辑。
4. 接口隔离原则(ISP)
两次代码均有:
RateStrategy 接口仅包含 calculateRate() 方法,无冗余。
Payment 抽象类仅定义 pay() 方法,符合最小接口原则。
这使得代码更加精简
5. 依赖倒置原则(DIP)
第一次代码:
Order 直接依赖具体的 Customer 类,未通过抽象。
第二次代码优化:
Order 改为依赖抽象的 Customer 类,通过 getDiscountRate() 实现折扣计算:
通过抽象化客户类型,更符合 DIP。
6. 迪米特法则(LoD)
两次代码均时:
Main 类直接操作多个具体类(如 Customer, Order, Flight),耦合度较高,这也是我这次大作业中代码设计最不合理的部分,需要改进。
7.组合/聚合复用原则(CARP)
第一次代码:
使用 LinkedList 聚合货物项,通过 RateStrategy 组合实现费率计算。
第二次代码优化:
策略模式:通过组合 RateStrategy 实现多类型费率。
客户折扣策略:通过组合 Customer 子类实现灵活折扣。
结论:
两次代码均优先使用组合而非继承,符合 CARP。

三、踩坑心得
1.类设计不可忽视,写代码的第一步永远是做类的设计。类的设计没有做好、类的方法以及类与类之间的关系没有设计清楚,写代码时很容易出现代码行多余、重复,而且非常不利于后续代码需求增加或修改,会给后续代码维护与升级造成非常大的负担。比如说我在第一次航空题目中将顾客类设置为具体类,没有考虑到顾客类型的不同,导致第二次代码改动变大而且原代码发生改变,这违背了开闭原则,每次改动都像是在“打补丁”,而不是只需增加子类代码。

  1. 动态输入处理的复杂性
    第二次代码支持动态输入客户类型、货物类型和支付方式,但Main类中大量使用if-else判断类型。例如,读取货物类型后需要根据字符串创建不同子类,一旦新增类型,Main类需要频繁改动,好比如我的第一次代码 读入不符导致报错

3.代码折扣计算的编码逻辑不够合理,第一次的订单总金额直接累加运费,没有折扣逻辑。第二次虽然加了客户折扣,但如果在其他模块(如退款逻辑)也需要折扣计算,代码会重复。比如,订单类直接调用customer.getDiscountRate(),如果未来折扣规则变化(如节假日促销),需要修改多个地方,维护难而且成本高。

四、改进建议
1.通过工厂模式实现对象的解耦合,为每类对象(货物、客户、支付)定义工厂类,封装创建逻辑,从而解决 Main 类中通过 if-else 判断动态创建对象(如货物、客户、支付方式),导致代码难以扩展而十分冗余的问题。
2. 问题:Main 类直接操作 Customer、Order、Flight 等对象,违反 迪米特法则。
改进:封装订单创建、校验和输出逻辑。
3. 增加枚举类型:
使用枚举定义货物类型、客户类型和支付方式,减少字符串硬编码,减少代码冗余程度。
4.减少对象间直接交互:通过中介者模式(Mediator)降低类间耦合。比如在加入订单操作类而非只通过order实现订单类的全部方法。
5. 组合替代多层继承:当子类难以完全兼容父类行为时,优先使用组合而非继承。比如说GoodsItem类,它更加适合用组合替代继承增强策略灵活性。比如说
改进:在GoodsItem中增加setRateStrategy()方法:
五、总结
1.设计原则的实践与理解
开闭原则(OCP):通过策略模式(RateStrategy)和抽象类(GoodsItem、Customer),实现了在不修改已有代码的前提下扩展新功能(如新增支付方式、客户类型)。允许通过扩展而非修改代码来应对需求变化,避免引入新 bug
单一职责原则(SRP):将运费计算、折扣逻辑、对象创建等职责分离到不同类中(如 RateStrategy、Customer 子类、工厂类),提升代码模块化。可以降低类的复杂度,避免因职责耦合导致的牵一发而动全身。
依赖倒置原则(DIP):Order 类依赖抽象的 Customer,而非具体实现,降低耦合。Order 依赖抽象的 Customer(getDiscountRate()),而非具体客户类型。
里氏替换原则(LSP):保证继承体系的可靠性,避免因子类行为异常导致程序崩溃。WechatPayment 和 Alipayment 无缝替换 Payment 抽象类,输出逻辑一致。
接口隔离原则(ISP):避免接口臃肿,让类仅实现所需功能,提升内聚性。RateStrategy 接口仅定义 calculateRate() 方法,无冗余方法。
迪米特法则(LOD):一个对象应尽可能少地了解其他对象。可以降低对象间耦合,减少系统变更的影响范围。Main 类直接操作多个对象,可引入服务类封装逻辑(如 OrderService)
合成复用原则(CRP):优先使用组合 / 聚合而非继承来复用代码。可以避免继承导致的强耦合,保持类的独立性和灵活性。GoodsItem 组合 RateStrategy 实现费率计算,而非通过继承硬编码。

2.设计模式的应用
策略模式:通过 RateStrategy 接口实现多类型费率计算,支持动态扩展(危险品、加急货物等)。
工厂模式:通过工厂类(如 GoodsItemFactory)封装对象创建逻辑,减少 Main 类的复杂度。

3.代码结构的优化
从具体到抽象:第二次代码将 GoodsItem 改为抽象类,子类通过继承绑定策略,提升扩展性。
组合优于继承:通过组合 RateStrategy 实现灵活的策略切换,而非硬编码在子类中。

posted @ 2025-05-24 19:02  bxsvtbkp  阅读(67)  评论(0)    收藏  举报