航空货运系统总结
一.前言:为什么要写航空货运系统?
航空货运系统作为新手编程项目,涉及多个模块的类设计以及多个编程原则比如单一职责原则、里氏代换原则、开闭原则以及合成复用原则、依赖倒转原则,非常适合新手练习。
二.类设计思路
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
类图如下:

四.总结
- 单一职责原则-----类设计时拆分功能模块
- 里氏代换原则-----设计继承体系时确保子类行为一致
- 开闭原则-----新增功能时避免修改原有代码
- 合成复用原则-----实现代码复用时避免滥用继承

浙公网安备 33010602011771号