航空货运系统总结

一.前言:为什么要写航空货运系统?

航空货运系统作为新手编程项目,涉及多个模块的类设计以及多个编程原则比如单一职责原则、里氏代换原则、开闭原则以及合成复用原则、依赖倒转原则,非常适合新手练习。

二.类设计思路

1.在处理客户需求时,将需求拆分成不同的逻辑处理模块。

比如航空货运系统中javaBean类有:客户,货物 ,支付方式,订单信息
工具类有:打印信息,计算运费,支付

2.自下往上设计,逐步抽象

比如在支付方式中,有三种不同的支付方式,但是除了姓名其他的并未有什么区别,那么在设计时可以逐步向上抽象,形成一个抽象的父类Payment,以及一个抽象的支付接口PayMathed其他支付方式,均继承自父类以及这个抽象接口,从而实现程序的可拓展性

3.判断耦合性,减少代码复杂度

比如订单信息虽然是一个javaBean类,只管理订单信息,但是运费的计算与其息息相关,并且还与运输方式类息息相关,所以运费计算需要耦合在订单内部,代码如下:

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Order {
    private String orderId;
    private Customer customer;
    private Date orderDate;
    private Person sender;
    private Person receiver;
    private Transport transport;
    private List<OrderItem> items = new ArrayList<>();
    private double totalWeight;
    private double totalFee;

    public Order(Customer customer) {
        this.customer = customer;
    }

    public void addItem(OrderItem item) {
        items.add(item);
    }

    public void setOrderDetails(String orderId, Date orderDate, Person sender, Person receiver) {
        this.orderId = orderId;
        this.orderDate = orderDate;
        this.sender = sender;
        this.receiver = receiver;
    }

    public void setTransport(Transport transport) {
        this.transport = transport;
    }

    public void calculateFees(FeeCalculator calculator) {
        if (transport == null) {
            throw new IllegalStateException("运输工具未设置");
        }
        
        totalWeight = 0;
        totalFee = 0;
        
        for (OrderItem item : items) {
            double itemWeight = calculator.calculateWeight(item);
            double itemFee = calculator.calculateFee(item, itemWeight);
            
            item.setBillingWeight(itemWeight);
            item.setFee(itemFee);
            
            totalWeight += itemWeight;
            totalFee += itemFee;
        }
        
        if (!transport.canCarry(totalWeight)) {
            throw new IllegalArgumentException("航班超载: " + transport.getIdentifier());
        }
    }

    // Getters
    public String getOrderId() { return orderId; }
    public Customer getCustomer() { return customer; }
    public Date getOrderDate() { return orderDate; }
    public Person getSender() { return sender; }
    public Person getReceiver() { return receiver; }
    public Transport getTransport() { return transport; }
    public List<OrderItem> getItems() { return items; }
    public double getTotalWeight() { return totalWeight; }
    public double getTotalFee() { return totalFee; }
}    

三.编程原则的运用

1.单一职责原则

打印类最开始的时候我设计在了订单信息类中,代码如下:

 public void printList() {
        double sum = 0;
        double sumCalculate = 0;
        for (int i = 0; i < order.getObjects().size(); i++) {
            sum += determineWeight(getGrossWeight(i), getVolumeWeight(i));
            sumCalculate += calculate(i);
        }
        if (buyType.equals("Individual")) {
            sumCalculate = sumCalculate * 0.9;
        } else if (buyType.equals("Corporate")) {
            sumCalculate = sumCalculate * 0.8;
        }
        if (planeMessage.getMaxWeight() < sum) {
            System.out.println("The flight with flight number:" + planeMessage.getName() + " has exceeded its load capacity and cannot carry the order.");
            System.exit(0);
        }
        System.out.println("客户:" + customer.getName() + "(" + customer.getPhoneNumber() + ")订单信息如下:");
        System.out.println("-----------------------------------------");
        System.out.println("航班号:" + planeMessage.getName());
        System.out.println("订单号:" + ID);
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
        String sdf2 = sdf1.format(date);
        System.out.println("订单日期:" + sdf2);
        System.out.println("发件人姓名:" + sender.getName());
        System.out.println("发件人电话:" + sender.getPhoneNumber());
        System.out.println("发件人地址:" + sender.getAddress());
        System.out.println("收件人姓名:" + receiver.getName());
        System.out.println("收件人电话:" + receiver.getPhoneNumber());
        System.out.println("收件人地址:" + receiver.getAddress());
        System.out.println("订单总重量(kg):" + sum);
        if (payType.equals("Wechat")) {
            System.out.println("微信支付金额:" + sumCalculate);
        } else if (payType.equals("ALiPay")) {
            System.out.println("支付宝支付金额:" + sumCalculate);
        } else if (payType.equals("Cash")) {
            System.out.println("现金支付金额:" + sumCalculate);
        }

        System.out.println("\n");
        System.out.println("货物明细如下:");
        System.out.println("-----------------------------------------");
        System.out.println("明细编号    货物名称    计费重量    计费费率    应交运费");

        for (int i = 0; i < order.getObjects().size(); i++) {
            System.out.println(i + 1 + "    " + order.getObjects().get(i).getName() + "    " +
                    determineWeight(getGrossWeight(i), getVolumeWeight(i)) +
                    "    " + calculate(i) / determineWeight(getGrossWeight(i), getVolumeWeight(i)) +
                    "    " + calculate(i));
        }
    }

但是在订单信息类中,它不仅要管理订单信息,还要进行运费计算,违反了单一职责原则,

单一职责原则:一个类或模块应该仅有一个引起其变化的原因,即每个类只负责一项单一的职责。
改进后,成为了一个独立的类``ConsoleOrderPrinter,只负责打印逻辑,其代码如下:

import model.Order;
import model.OrderItem;
import model.Transport;

import java.text.SimpleDateFormat;
import java.util.Date;

public class ConsoleOrderPrinter implements OrderPrinter {
    @Override
    public void printOrder(Order order) {
        try {
            Transport transport = order.getTransport();
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            
            System.out.println("客户:" + order.getCustomer().getName() + "(" + order.getCustomer().getPhoneNumber() + ")订单信息如下:");
            System.out.println("-----------------------------------------");
            System.out.println("航班号:" + transport.getIdentifier());
            System.out.println("订单号:" + order.getOrderId());
            System.out.println("订单日期:" + formatDate(order.getOrderDate(), dateFormat));
            System.out.println("发件人姓名:" + order.getSender().getName());
            System.out.println("发件人电话:" + order.getSender().getPhoneNumber());
            System.out.println("发件人地址:" + order.getSender().getAddress());
            System.out.println("收件人姓名:" + order.getReceiver().getName());
            System.out.println("收件人电话:" + order.getReceiver().getPhoneNumber());
            System.out.println("收件人地址:" + order.getReceiver().getAddress());
            System.out.println("订单总重量(kg):" + order.getTotalWeight());
            System.out.println("支付金额:" + order.getTotalFee() + " 元");
            System.out.print("\n");
            System.out.println("货物明细如下:");
            System.out.println("-----------------------------------------");
            System.out.println("明细编号    货物名称    计费重量    计费费率    应交运费");

            int index = 1;
            for (OrderItem item : order.getItems()) {
                System.out.printf("%d        %s        %.2f        %.2f        %.2f%n", 
                    index++,
                    item.getName(),
                    item.getBillingWeight(),
                    item.getFee() / item.getBillingWeight(),
                    item.getFee());
            }
        } catch (Exception e) {
            System.err.println("打印订单时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    private String formatDate(Date date, SimpleDateFormat format) {
        return date != null ? format.format(date) : "未知";
    }
}    

2.里氏代换原则

里氏代换原则:所有引用基类(父类)的地方必须能透明地使用其子类的对象,即子类必须完全实现父类的接口,且行为保持一致,且子类不能削弱父类定义的前置条件或强化后置条件。
也就是说,子类对象可以传给父类的引用,向上转型,从而实现多态,即多种状态,比如:public void pay(Payment payMent),而不是public void pay(AliPay aliPay)

3.开闭原则

开闭原则:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。即当需求变化时,优先通过扩展现有代码(新增模块 / 类)而非修改原有代码来实现
在第二次作业,拓展功能时,不是修改源码,而是再创建一个名字一样的类,使它的功能增加,比如原先的javaBean类为Order,再写一个类,名字还是Order

4.合成复用原则

合成复用原则:优先使用 ** 组合(Composition)或聚合(Aggregation)** 而非继承来实现代码复用,即 “has-a” 关系优于 “is-a” 关系。
比如Order类依赖Printer:打印功能通过组合实现,而非继承,从而减少了耦合性

输出结果:

客户:郭靖(13807911234)订单信息如下:
-----------------------------------------
航班号:MU1234
订单号:900001
订单日期:2025-04-22
发件人姓名:洪七公
发件人电话:18907912325
发件人地址:南昌大学
收件人姓名:黄药师
收件人电话:13607912546
收件人地址:北京大学
订单总重量(kg):125.0
支付宝支付金额:4360.0

货物明细如下:
-----------------------------------------
明细编号    货物名称    计费重量    计费费率    应交运费
1    发电机    80.0    40.0    3200.0
2    信号发生器    45.0    50.0    2250.0

类图如下:

四.总结

  • 单一职责原则-----类设计时拆分功能模块
  • 里氏代换原则-----设计继承体系时确保子类行为一致
  • 开闭原则-----新增功能时避免修改原有代码
  • 合成复用原则-----实现代码复用时避免滥用继承
posted @ 2025-05-25 19:56  严远钊  阅读(10)  评论(0)    收藏  举报