Bài toán quản lý vận tải hàng không yêu cầu xây dựng hệ thống xử lý đơn hàng dựa trên nguyên tắc đóng gói và kế thừa. Hệ thống cần tính toán trọng lượng tính cước theo công thức: trọng lượng thể tích (dài × rộng × cao / 6000) hoặc trọng lượng thực tế, lấy giá trị lớn hơn. Mức phí vận chuyển phụ thuộc vào loại hàng hóa và trọng lượng tính cước.
Dưới đây là triển khai cải tiến sử dụng lớp trừu tượng và đa hình. Lớp
HangHoa định nghĩa hành vi chung cho các loại hàng:
abstract class HangHoa {
protected String maHang;
protected String tenHang;
protected double chieuDai;
protected double chieuRong;
protected double chieuCao;
protected double trongLuongThuc;
public HangHoa(String ma, String ten, double dai, double rong, double cao, double trongLuong) {
this.maHang = ma;
this.tenHang = ten;
this.chieuDai = dai;
this.chieuRong = rong;
this.chieuCao = cao;
this.trongLuongThuc = trongLuong;
}
public double trongLuongTinhCuoc() {
double trongLuongTheTich = (chieuDai * chieuRong * chieuCao) / 6000.0;
return Math.max(trongLuongThuc, trongLuongTheTich);
}
public abstract double mucPhi();
public abstract double phiVanChuyen();
}
Các lớp cụ thể triển khai quy tắc tính phí riêng:
class HangThuong extends HangHoa {
public HangThuong(String... args) {
super(args[0], args[1], Double.parseDouble(args[2]),
Double.parseDouble(args[3]), Double.parseDouble(args[4]),
Double.parseDouble(args[5]));
}
@Override
public double mucPhi() {
double trongLuong = trongLuongTinhCuoc();
return trongLuong < 20 ? 35.0 :
trongLuong < 50 ? 30.0 :
trongLuong < 100 ? 25.0 : 15.0;
}
@Override
public double phiVanChuyen() {
return trongLuongTinhCuoc() * mucPhi();
}
}
class HangUuTien extends HangHoa {
public HangUuTien(String... args) { /* Tương tự */ }
@Override
public double mucPhi() {
double trongLuong = trongLuongTinhCuoc();
return trongLuong < 20 ? 60.0 :
trongLuong < 50 ? 50.0 :
trongLuong < 100 ? 40.0 : 30.0;
}
// ... phương thức phiVanChuyen
}
Lớp BoDieuHanh xử lý quy trình chính:
class BoDieuHanh {
private ChuyenBay chuyenBay;
private List<HangHoa> danhSachHang = new ArrayList<>();
public void themHang(HangHoa hang) {
danhSachHang.add(hang);
}
public boolean ktraTaiTrong() {
double tongTrongLuong = danhSachHang.stream()
.mapToDouble(HangHoa::trongLuongTinhCuoc)
.sum();
return tongTrongLuong <= chuyenBay.getTaiTrongToiDa();
}
public void xuatThongTin() {
if (!ktraTaiTrong()) {
System.out.printf("Chuyến bay %s vượt quá tải trọng cho phép%n",
chuyenBay.getMaChuyen());
return;
}
// Xuất thông tin đơn hàng
System.out.printf("Khách hàng: %s (%s) - Đơn hàng:%n",
khachHang.getTen(), khachHang.getSDT());
System.out.println("--------------------------------------------------");
System.out.println("Mã chuyến: " + chuyenBay.getMaChuyen());
// ... các thông tin khác
System.out.printf("Tổng trọng lượng (kg): %.1f%n",
danhSachHang.stream()
.mapToDouble(HangHoa::trongLuongTinhCuoc)
.sum());
System.out.println("Chi tiết hàng hóa:");
System.out.println("STT\tTên hàng\tTrọng lượng\tMức phí\tThành tiền");
IntStream.range(0, danhSachHang.size()).forEach(i -> {
HangHoa hang = danhSachHang.get(i);
System.out.printf("%d\t%s\t%.1f\t%.1f\t%.1f%n",
i+1, hang.tenHang, hang.trongLuongTinhCuoc(),
hang.mucPhi(), hang.phiVanChuyen());
});
}
}
Cơ chế thanh toán được triển khai qua đa hình:
abstract class HinhThucThanhToan {
public abstract void hienThiTen();
}
class ThanhToanQR extends HinhThucThanhToan {
@Override
public void hienThiTen() {
System.out.print("Số tiền qua Momo: ");
}
}
class ThanhToanTienMat extends HinhThucThanhToan {
@Override
public void hienThiTen() {
System.out.print("Số tiền mặt: ");
}
}
Điểm cải tiến so với thiết kế ban đầu:
- Tách biệt logic tính trọng lượng vào lớp HangHoa
- Sử dụng stream API để tính tổng trọng lượng
- Thay thế cấu trúc if-else bằng biểu thức ternary
- Tối ưu hóa việc xử lý loại hàng hóa qua kế thừa
- Giảm độ phức tạp của lớp điều khiển chính
- Dễ dàng mở rộng khi thêm loại hàng mới
Hệ thống đảm bảo tính toàn vẹn dữ liệu khi kiểm tra tải trọng trước khi xử lý đơn hàng. Định dạng đầu ra tuân thủ yêu cầu với số thực làm tròn 1 chữ số thập phân.