Quản lý khách hàng: o Thêm, hiển thị, tìm kiếm khách hàng theo mã.. Lưu trữ dữ liệu: o Lưu danh sách khách hàng vào file nhị phân .dat.. o Phương thức: Thêm, hiển thị, tìm kiếm, lưu/đọ
Trang 1TRƯỜNG ĐẠI HỌC MỞ HÀ NỘI KHOA CÔNG NGHỆ THÔNG TIN
BÁO CÁO BÀI TẬP LỚN Môn học: KỸ THUẬT LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG
Đề bài: “Bài toán quản lý mượn trả sách thư viện”
Giảng viên giảng dạy: Nguyễn Thành Huy Sinh viên thực hiện: Nguyễn Công Vinh
Phan Minh Trí
Trần Ngô Tú Anh
Lớp: 2410A07
Hà Nội, ngày 14 tháng 4 năm 2025
Trang 2I.Xác định và mô tả bài toán:
Yêu cầu chức năng:
1 Quản lý khách hàng:
o Thêm, hiển thị, tìm kiếm khách hàng theo mã
o Lưu trữ thông tin: mã KH, họ tên, địa chỉ, số điện cũ, số điện mới
2 Tính toán hóa đơn:
o Tự động tính số điện sử dụng: Số điện mới - Số điện cũ
o Tính tiền điện theo đơn giá cố định (3.000 VND/kWh)
o In hóa đơn với mã hóa đơn tự động (HD + mã KH)
3 Lưu trữ dữ liệu:
o Lưu danh sách khách hàng vào file nhị phân .dat
o Đọc dữ liệu từ file để tiếp tục làm việc
Yêu cầu phi chức năng:
1 Áp dụng OOP:
o Kế thừa: Lớp KhachHang kế thừa từ lớp trừu tượng Nguoi.
o Đa hình: Lớp HoaDon triển khai interface IHoaDon (phương
thức tinhTienDien() và inHoaDon())
o Đóng gói: Các thuộc tính được khai báo private và truy cập
qua getter
2 Xử lý ngoại lệ:
o Kiểm tra đầu vào (ví dụ: số điện không âm)
o Xử lý lỗi khi đọc/ghi file (sử dụng try-catch)
Các lớp và thành phần chính:
1 Lớp Nguoi (Abstract):
o Thuộc tính: hoTen, diaChi.
o Phương thức trừu tượng: hienThiThongTin().
2 Lớp KhachHang (Kế thừa Nguoi):
o Thuộc tính mở rộng: maKhachHang, soDienCu, soDienMoi.
Trang 3o Phương thức:
hienThiThongTin(): Hiển thị thông tin và tạo hóa đơn
3 Lớp HoaDon (Implement IHoaDon):
o Thuộc tính: khachHang, soDienSuDung, maHoaDon.
o Phương thức:
tinhTienDien(): Tính tiền điện dựa trên số điện sử dụng
inHoaDon(): In thông tin hóa đơn
4 Lớp QuanLyKhachHang:
o Thuộc tính: danhSach (ArrayList<KhachHang>).
o Phương thức:
Thêm, hiển thị, tìm kiếm, lưu/đọc file
5 Lớp Main:
o Phương thức main(): Hiển thị menu và xử lý lựa chọn người dùng.
II.Xác định Sơ đồ lớp của bài toán
Trang 4III.Mô tả thuật toán-các thao tác nghiệp vụ cần xử lý
1 Thuật toán nhập thông tin khách hàng
Mục đích: Thêm khách hàng mới vào danh sách.
Các bước:
1 Yêu cầu người dùng nhập số lượng khách hàng
2 Với mỗi khách hàng:
Nhập mã khách hàng (kiểm tra trùng lặp).
Nhập tên, địa chỉ.
Nhập số điện cũ và số điện mới (đảm bảo số điện mới ≥ số
điện cũ)
3 Tạo đối tượng KhachHang và thêm vào ArrayList<KhachHang>
Xử lý nghiệp vụ:
o Kiểm tra tính hợp lệ của dữ liệu (ví dụ: số điện không âm)
o Đảm bảo mã khách hàng là duy nhất
2 Thuật toán hiển thị danh sách khách hàng và hóa đơn
Mục đích: Hiển thị thông tin khách hàng và hóa đơn tương ứng.
Các bước:
1 Duyệt qua từng phần tử trong ArrayList<KhachHang>
2 In thông tin khách hàng sử dụng toString()
3 Tạo đối tượng HoaDon từ KhachHang và gọi inHoaDon()
Xử lý nghiệp vụ:
o Kiểm tra danh sách có rỗng không
o Định dạng đầu ra cho dễ đọc (ví dụ: thêm tiêu đề, phân cách)
3 Thuật toán tìm kiếm khách hàng theo mã
Trang 5 Mục đích: Tìm kiếm và hiển thị thông tin khách hàng dựa trên mã.
Các bước:
1 Nhập mã khách hàng từ người dùng.
2 Duyệt danh sách ArrayList<KhachHang>
3 So sánh mã khách hàng với giá trị nhập vào
4 Nếu tìm thấy, hiển thị thông tin và hóa đơn
5 Nếu không, thông báo "Không tìm thấy"
Xử lý nghiệp vụ:
o Xử lý trường hợp mã không tồn tại
o Phân biệt chữ hoa/chữ thường (nếu cần)
4 Thuật toán lưu và đọc dữ liệu từ file
Lưu dữ liệu:
1 Mở luồng ghi (ObjectOutputStream)
2 Ghi đối tượng ArrayList<KhachHang> vào file quanLyTienDien.dat
3 Đóng luồng và thông báo thành công
Đọc dữ liệu:
1 Mở luồng đọc (ObjectInputStream)
2 Đọc đối tượng từ file và ép kiểu về ArrayList<KhachHang>
3 Đóng luồng và thông báo thành công
Xử lý nghiệp vụ:
o Kiểm tra file tồn tại trước khi đọc
o Xử lý ngoại lệ ClassNotFoundException (nếu cấu trúc lớp thay đổi)
5 Thuật toán tính tiền điện (HoaDon)
Mục đích: Tính toán số tiền điện phải trả.
Công thức:
Tiền điện = (Số điện mới - Số điện cũ) * Đơn giá
(Hiện tại: Đơn giá mặc định là 3000 đồng/kWh)
Xử lý nghiệp vụ:
o Áp dụng các mức giá theo bậc thang (ví dụ: 0-50 kWh: 2000đ, 51-100 kWh: 2500đ, )
Trang 6o Làm tròn số tiền (nếu cần).
6 Xử lý ngoại lệ và kiểm tra dữ liệu
Kiểm tra dữ liệu nhập:
o Số điện phải là số nguyên dương
o Số điện mới ≥ số điện cũ
o Mã khách hàng không được trùng
Xử lý ngoại lệ:
o InputMismatchException: Khi nhập sai kiểu dữ liệu (ví dụ: nhập chữ vào số)
o FileNotFoundException: Khi file không tồn tại
o IOException: Lỗi đọc/ghi file
IV.Cài đặt bài toán
1.Class Nguoi
package quanlytiendien;
import java.io.Serializable;
public abstract class Nguoi implements Serializable {
protected String hoTen;
protected String diaChi;
public Nguoi(String hoTen, String diaChi) {
this.hoTen = hoTen;
this.diaChi = diaChi;
}
public Nguoi() {
}
public String getHoTen() {
return hoTen;
}
public String getDiaChi() {
return diaChi;
}
public abstract void hienThiThongTin();
}
2.Class KhachHang
Trang 7package quanlytiendien;
import java.io.Serializable;
public class KhachHang extends Nguoi implements Serializable {
private static final long serialVersionUID = 1L;
private String maKhachHang;
private int soDienCu;
private int soDienMoi;
public KhachHang() {
super();
}
public KhachHang(String hoTen, String diaChi, String maKhachHang, int soDienCu, int soDienMoi) {
super(hoTen, diaChi);
this.maKhachHang = maKhachHang;
this.soDienCu = soDienCu;
this.soDienMoi = soDienMoi;
}
public String getMaKhachHang() {
return maKhachHang;
}
public int getSoDienCu() {
return soDienCu;
}
public int getSoDienMoi() {
return soDienMoi;
}
@Override
public String toString() {
return "Mã Khách Hàng: " + maKhachHang + "\n" +
"Họ Tên: " + hoTen + "\n" +
"Địa Chỉ: " + diaChi + "\n" +
"Số Điện Cũ: " + soDienCu + "\n" +
"Số Điện Mới: " + soDienMoi;
}
@Override
public void hienThiThongTin() {
Trang 8System.out.println(this.toString());
}
}
3.Class HoaDon
package quanlytiendien;
import java.io.Serializable;
public class HoaDon implements IHoaDon, Serializable {
private static final long serialVersionUID = 1L;
private KhachHang khachHang;
private int soDienSuDung;
private String maHoaDon;
public HoaDon(KhachHang khachHang) {
this.khachHang = khachHang;
this.soDienSuDung = khachHang.getSoDienMoi() -
khachHang.getSoDienCu();
this.maHoaDon = "HD_" + khachHang.getMaKhachHang(); }
@Override
public double tinhTienDien() {
double donGia = 3000;
return soDienSuDung * donGia;
}
@Override
public void inHoaDon() {
System.out.println(this.toString());
}
@Override
public String toString() {
return "Mã Hoá Đơn: " + maHoaDon + "\n" +
"Số Điện Sử Dụng: " + soDienSuDung + "\n" +
"Tiền Điện: " + tinhTienDien() + " Đồng";
}
}
4.Class IHoaDon
package quanlytiendien;
Trang 9public interface IHoaDon {
void inHoaDon();
double tinhTienDien();
}
5.Class QuanLyKhachHang
package quanlytiendien;
import java.util.ArrayList;
import java.util.Scanner;
import java.io.*;
public class QuanLyKhachHang {
private ArrayList<KhachHang> danhSach;
public QuanLyKhachHang() {
danhSach = new ArrayList<>();
}
Scanner sc = new Scanner(System.in);
public void nhapThongTinKhachHang() {
System.out.print("Nhập Số Lượng Khách Hàng: ");
int soLuong = sc.nextInt();
sc.nextLine();
for (int i = 0; i < soLuong; i++) {
System.out.println("NHẬP THÔNG TIN KHÁCH HÀNG " + (i + 1)); System.out.print("Nhập Mã Khách Hàng: ");
String maKhachHang = sc.nextLine();
System.out.print("Nhập Tên Khách Hàng: ");
String hoTen = sc.nextLine();
System.out.print("Nhập Địa Chỉ: ");
String diaChi = sc.nextLine();
System.out.print("Nhập Số Điện Cũ: ");
int soDienCU = sc.nextInt();
System.out.print("Nhập Số Điện Mới: ");
int soDienMoi = sc.nextInt();
sc.nextLine();
KhachHang khachHang = new KhachHang(hoTen, diaChi, maKhachHang, soDienCU, soDienMoi);
danhSach.add(khachHang);
}
}
public void hienThiThongTinKhachHang() {
System.out.println("=====DANH SÁCH KHÁCH HÀNG=====");
Trang 10for (KhachHang khachHang : danhSach) {
System.out.println(khachHang.toString());
HoaDon hoaDon = new HoaDon(khachHang);
hoaDon.inHoaDon();
System.out.println(" -");
}
}
public void timKhachHang() {
System.out.print("Nhập Mã Khách Hàng Để Tìm: ");
String maKhachHang = sc.nextLine();
boolean timKiem = false;
for (KhachHang khachHang : danhSach) {
if (khachHang.getMaKhachHang().equals(maKhachHang)) {
System.out.println(khachHang.toString());
HoaDon hoaDon = new HoaDon(khachHang);
hoaDon.inHoaDon();
timKiem = true;
break;
}
}
if (!timKiem) {
System.out.println("Không tìm thấy khách hàng với mã: " +
maKhachHang);
}
}
public void luuFile(String tenFile) {
try (ObjectOutputStream file = new ObjectOutputStream(new FileOutputStream(tenFile))) {
for (KhachHang khachHang : danhSach) {
HoaDon hoaDon = new HoaDon(khachHang);
file.writeObject(khachHang);
file.writeObject(hoaDon);
}
System.out.println("Đã Lưu File");
} catch (IOException x) {
x.printStackTrace();
}
}
Trang 11public void docFile(String tenFile) {
try (ObjectInputStream file = new ObjectInputStream(new
FileInputStream(tenFile))) {
boolean hasData = false;
while (true) {
try {
KhachHang khachHang = (KhachHang) file.readObject(); HoaDon hoaDon = (HoaDon) file.readObject();
danhSach.add(khachHang);
System.out.println(khachHang.toString());
hoaDon.inHoaDon();
hasData = true;
} catch (ClassNotFoundException | EOFException e) {
break;
}
}
if (!hasData) {
System.out.println("Không có dữ liệu khách hàng trong file.");
} else {
System.out.println("Đọc file thành công.");
}
} catch (IOException x) {
System.out.println("Có lỗi xảy ra khi đọc file: " + x.getMessage());
}
}
}
6.Class Main
package quanlytiendien;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
QuanLyKhachHang qlKH = new QuanLyKhachHang();
while (true) {
System.out.println("===== MENU QUẢN LÝ TIỀN ĐIỆN ====="); System.out.println("1 Nhập thông tin khách hàng");
System.out.println("2 Hiển thị danh sách khách hàng và hóa đơn"); System.out.println("3 Tìm khách hàng theo mã");
System.out.println("4 Lưu thông tin khách hàng vào file");
System.out.println("5 Đọc thông tin khách hàng từ file");
System.out.println("6 Thoát");
System.out.print("Chọn chức năng (1-6): ");
Trang 12int luaChon = sc.nextInt();
sc.nextLine();
switch (luaChon) {
case 1:
qlKH.nhapThongTinKhachHang();
break;
case 2:
qlKH.hienThiThongTinKhachHang();
break;
case 3:
qlKH.timKhachHang();
break;
case 4:
qlKH.luuFile("quanLyTienDien.dat");
break;
case 5:
qlKH.docFile("quanLyTienDien.dat");
break;
case 6:
System.out.println("Thoát!");
return;
default:
System.out.println("Lựa chọn không hợp lệ Vui lòng chọn lại.");
break;
}
}
}
}
Test Case 1: Nhập thông tin khách hàng
Mô tả: Nhập thông tin cho 2 khách hàng
Dữ liệu nhập:
Nhập Số Lượng Khách Hàng: 2
Nhập Mã Khách Hàng: KH01
Nhập Tên Khách Hàng: Nguyen Van A
Nhập Địa Chỉ: 123 ABC
Nhập Số Điện Cũ: 100
Nhập Số Điện Mới: 150
Nhập Mã Khách Hàng: KH02
Nhập Tên Khách Hàng: Tran Thi B
Nhập Địa Chỉ: 456 DEF
Nhập Số Điện Cũ: 200
Trang 13Nhập Số Điện Mới: 250
Test Case 2: Hiển thị danh sách khách hàng và hóa đơn
Kết quả mong đợi:
=====DANH SÁCH KHÁCH HÀNG=====
Mã Khách Hàng: KH01
Họ Tên: Nguyen Van A
Địa Chỉ: 123 ABC
Số Điện Cũ: 100
Số Điện Mới: 150
Mã Hoá Đơn: HD_KH01
Số Điện Sử Dụng: 50
Tiền Điện: 150000.0 Đồng
Mã Khách Hàng: KH02
Họ Tên: Tran Thi B
Địa Chỉ: 456 DEF
Số Điện Cũ: 200
Số Điện Mới: 250
Mã Hoá Đơn: HD_KH02
Số Điện Sử Dụng: 50
Tiền Điện: 150000.0 Đồng
Test Case 3: Tìm khách hàng theo mã
Mã Khách Hàng: KH01
Kết quả mong đợi:
Mã Khách Hàng: KH01
Họ Tên: Nguyen Van A
Địa Chỉ: 123 ABC
Số Điện Cũ: 100
Số Điện Mới: 150
Mã Hoá Đơn: HD_KH01
Số Điện Sử Dụng: 50
Tiền Điện: 150000.0 Đồng
Test Case 4: Lưu thông tin vào file
Tên file: khachhang.dat
Kết quả mong đợi:
Đã Lưu File
Test Case 5: Đọc thông tin từ file
Tên file: khachhang.dat
Kết quả mong đợi:
Đọc file thành công
Mã Khách Hàng: KH01
Họ Tên: Nguyen Van A
Địa Chỉ: 123 ABC
Trang 14Số Điện Cũ: 100
Số Điện Mới: 150
Mã Hoá Đơn: HD_KH01
Số Điện Sử Dụng: 50 Tiền Điện: 150000.0 Đồng
Mã Khách Hàng: KH02
Họ Tên: Tran Thi B
Địa Chỉ: 456 DEF
Số Điện Cũ: 200
Số Điện Mới: 250
Mã Hoá Đơn: HD_KH02
Số Điện Sử Dụng: 50 Tiền Điện: 150000.0 Đồng