diff --git a/hinh_chu_nhat/HinhChuNhat.java b/hinh_chu_nhat/HinhChuNhat.java index 10af7ef..6cdecc4 100644 --- a/hinh_chu_nhat/HinhChuNhat.java +++ b/hinh_chu_nhat/HinhChuNhat.java @@ -5,33 +5,38 @@ import static yan_service.YANConstant.*; import static yan_service.YANService.*; +/** + * Tóm tắt: Lưu thông tin một hình chữ nhật và xử lý nhập, tính chu vi, diện + * tích, xuất kết quả ra console. + */ public class HinhChuNhat { - // #region Fields + // Nhóm dữ liệu đầu vào và kết quả tính toán của hình chữ nhật. private double chieuDai; private double chieuRong; private double chuVi; private double dienTich; - // #endregion - // #region Methods + // Tính chu vi theo công thức 2 * (dài + rộng). public void tinhChuVi() { chuVi = 2 * (chieuDai + chieuRong); } + // Tính diện tích theo công thức dài * rộng. public void tinhDienTich() { dienTich = chieuDai * chieuRong; } public void nhapChieuDai() { printAdv(GREEN, "Chiều dài: ", RESET); - chieuDai = numLimit(0, MAX_VALUE); + chieuDai = numLimitEx(0, MAX_VALUE); } public void nhapChieuRong() { printAdv(GREEN, "Chiều rộng: ", RESET); - chieuRong = numLimit(0, MAX_VALUE); + chieuRong = numLimitEx(0, MAX_VALUE); } + // Nhập đủ dữ liệu rồi cập nhật ngay hai giá trị dẫn xuất. public void nhapHinhChuNhat() { nhapChieuDai(); nhapChieuRong(); @@ -61,9 +66,8 @@ public void xuatHinhChuNhat() { xuatChuVi(); xuatDienTich(); } - // #endregion - // #region Properties + // Nhóm getter/setter phục vụ tái sử dụng đối tượng trong bài tập khác. public double getChieuDai() { return chieuDai; } @@ -95,5 +99,4 @@ public double getDienTich() { // public void setDienTich(double dienTich) { // this.dienTich = dienTich; // } - // #endregion } diff --git a/hinh_chu_nhat/TinhHinhChuNhat.java b/hinh_chu_nhat/TinhHinhChuNhat.java index 98ce11c..769ecbb 100644 --- a/hinh_chu_nhat/TinhHinhChuNhat.java +++ b/hinh_chu_nhat/TinhHinhChuNhat.java @@ -8,21 +8,23 @@ import static yan_service.YANConstant.*; import static yan_service.YANService.*; +/** + * Tóm tắt: Chương trình console nhập nhiều hình chữ nhật rồi in chu vi và diện + * tích của từng hình. + */ public class TinhHinhChuNhat { public static void main(String[] args) { - // tit + // In tiêu đề bài trước khi vào vòng nhập liệu chính. out.println(BLUE_BOLD); printlnAdv("Bài Tính Hình Chữ Nhật"); - // content run(); } - // Fields + // Danh sách hình chữ nhật được nhập trong một lượt chạy. private static List mDSHinhChuNhat; - // Main + // Điều phối nhập số lượng hình, nhập từng hình và xuất kết quả. private static void run() { - // input out.println(); printAdv(GREEN, "Nhập vào số hình chữ nhật: ", RESET); var n = numLimit(1, MAX_VALUE); @@ -34,14 +36,12 @@ private static void run() { hinhChuNhat.nhapHinhChuNhat(); mDSHinhChuNhat.add(hinhChuNhat); } - // output out.println(YELLOW); showntime(); - // ctrl checkOut(); } - // Showntime + // In kết quả đã tính cho toàn bộ hình chữ nhật trong danh sách. private static void showntime() { for (var i = 0; i < mDSHinhChuNhat.size(); i++) { printlnAdv(format("Hình chữ nhật thứ %d", i + 1)); @@ -50,7 +50,7 @@ private static void showntime() { } } - // Check out + // Cho phép người dùng chạy lại bài mà không phải khởi động chương trình. private static void checkOut() { if (credit() == 1) { run(); diff --git a/quan_ly_hoc_sinh/BaoHiemYTe.java b/quan_ly_hoc_sinh/BaoHiemYTe.java index 3c04a6b..c929f09 100644 --- a/quan_ly_hoc_sinh/BaoHiemYTe.java +++ b/quan_ly_hoc_sinh/BaoHiemYTe.java @@ -7,17 +7,20 @@ import static yan_service.YANConstant.*; import static yan_service.YANService.*; +/** + * Tóm tắt: Lưu thông tin bảo hiểm y tế của học sinh, gồm số phiếu, ngày cấp, + * bệnh viện đăng ký và thời hạn hiệu lực. + */ public class BaoHiemYTe { - // #region Fields + // Các thuộc tính bám sát thông tin thường có trên thẻ/phiếu BHYT. private String soPhieu; private Date ngayCap; private String tenBVDK; private Date tuNgay; private Date denNgay; private final Scanner mScan = new Scanner(in); - // #endregion - // #region Methods + // Nhóm hàm nhập từng trường giúp luồng nhập chính dễ đọc và dễ kiểm tra. public void nhapSoPhieu() { printAdv(GREEN, "Số phiếu BHYT: ", RESET); soPhieu = mScan.nextLine(); @@ -78,9 +81,8 @@ public void xuatBaoHiemYTe() { xuatTuNgay(); xuatDenNgay(); } - // #endregion - // #region Properties + // Getter/setter phục vụ tổng hợp thông tin học sinh ở các lớp khác. public String getSoPhieu() { return soPhieu; } @@ -120,5 +122,4 @@ public Date getDenNgay() { public void setDenNgay(Date denNgay) { this.denNgay = denNgay; } - // #endregion } diff --git a/quan_ly_hoc_sinh/DiemTungMon.java b/quan_ly_hoc_sinh/DiemTungMon.java index bb2f182..32ff978 100644 --- a/quan_ly_hoc_sinh/DiemTungMon.java +++ b/quan_ly_hoc_sinh/DiemTungMon.java @@ -4,16 +4,19 @@ import static yan_service.YANConstant.*; import static yan_service.YANService.*; +/** + * Tóm tắt: Quản lý điểm thành phần của một môn học trong một học kỳ và tính + * điểm trung bình môn theo trọng số miệng, 15 phút, giữa kỳ, cuối kỳ. + */ public class DiemTungMon { - // #region Fiedls + // Điểm thành phần và điểm trung bình đã tính của một môn. private double diemKTMieng; private double diemKT15Phut; private double diemKTGiuaKy; private double diemKTCuoiKy; private double diemTrungBinhMon; - // #endregion - // #region Methods + // Công thức trọng số: miệng 1, 15 phút 1, giữa kỳ 2, cuối kỳ 3. public void tinhDiemTrungBinhMon() { diemTrungBinhMon = (diemKTMieng + diemKT15Phut + diemKTGiuaKy * 2 + diemKTCuoiKy * 3) / 7; } @@ -73,9 +76,8 @@ public void xuatDiemTungMon(String monHoc, int hocKy) { xuatDiemKTCuoiKy(monHoc, hocKy); xuatDiemTrungBinhMon(monHoc, hocKy); } - // #endregion - // #region Properties + // Getter/setter cho điểm thành phần; điểm trung bình chỉ nên tính bằng công thức. public double getDiemKTMieng() { return diemKTMieng; } @@ -115,5 +117,4 @@ public double getDiemTrungBinhMon() { // public void setDiemTrungBinhMon(double diemTrungBinhMon) { // this.diemTrungBinhMon = diemTrungBinhMon; // } - // #endregion } diff --git a/quan_ly_hoc_sinh/HocSinh.java b/quan_ly_hoc_sinh/HocSinh.java index 0b2cd27..968a6ba 100644 --- a/quan_ly_hoc_sinh/HocSinh.java +++ b/quan_ly_hoc_sinh/HocSinh.java @@ -7,16 +7,19 @@ import static yan_service.YANConstant.*; import static yan_service.YANService.*; +/** + * Tóm tắt: Gộp mã học sinh, thông tin cá nhân, thông tin trường/lớp và thành + * tích học tập thành một hồ sơ học sinh hoàn chỉnh. + */ public class HocSinh { - // #region Fields + // Mỗi hồ sơ học sinh được chia thành các cụm thông tin nhỏ để dễ quản lý. private String maHocSinh; private ThongTinCaNhan thongTinCaNhan; private ThongTinCoBan thongTinCoBan; private ThanhTichHocTap thanhTichHocTap; private final Scanner mScan = new Scanner(in); - // #endregion - // #region Methods + // Nhóm hàm nhập từng phần của hồ sơ học sinh. public void nhapMaHocSinh() { printAdv(GREEN, "Mã học sinh: ", RESET); maHocSinh = mScan.nextLine(); @@ -66,9 +69,8 @@ public void xuatHocSinh() { xuatThongTinCoBan(); xuatThanhTichHocTap(); } - // #endregion - // #region Properties + // Getter/setter hỗ trợ màn hình quản lý truy cập từng cụm thông tin. public String getMaHocSinh() { return maHocSinh; } @@ -100,5 +102,4 @@ public ThanhTichHocTap getThanhTichHocTap() { public void setThanhTichHocTap(ThanhTichHocTap thanhTichHocTap) { this.thanhTichHocTap = thanhTichHocTap; } - // #endregion } diff --git a/quan_ly_hoc_sinh/QuanLyHocSinh.java b/quan_ly_hoc_sinh/QuanLyHocSinh.java index 88f6ea0..3f4fbc6 100644 --- a/quan_ly_hoc_sinh/QuanLyHocSinh.java +++ b/quan_ly_hoc_sinh/QuanLyHocSinh.java @@ -8,21 +8,23 @@ import static yan_service.YANConstant.*; import static yan_service.YANService.*; +/** + * Tóm tắt: Chương trình console nhập danh sách học sinh, kiểm tra trùng mã và + * in tóm tắt thành tích học tập của từng học sinh. + */ public class QuanLyHocSinh { public static void main(String[] args) { - // tit + // In tiêu đề trước khi bắt đầu luồng nhập danh sách. out.println(BLUE_BOLD); printlnAdv("Bài Tập Quản Lý Học Sinh"); - // content run(); } - // Fields + // Danh sách học sinh trong một lượt chạy chương trình. private static List mDSHocSinh; - // Main + // Điều phối nhập số lượng, nhập từng học sinh, xuất kết quả và hỏi tiếp tục. private static void run() { - // input out.println(); printAdv(GREEN, "Nhập vào số học sinh: ", RESET); var n = numLimit(1, MAX_VALUE); @@ -39,14 +41,12 @@ private static void run() { hocSinh.nhapThanhTichHocTap(); mDSHocSinh.add(hocSinh); } - // output out.println(YELLOW); showntime(); - // ctrl checkOut(); } - // Check regist + // Kiểm tra mã học sinh đã tồn tại trong danh sách hiện tại hay chưa. private static boolean isRegist(String maHocSinh) { var isSuccess = false; for (var hocSinh : mDSHocSinh) { @@ -59,7 +59,7 @@ private static boolean isRegist(String maHocSinh) { return isSuccess; } - // Showntime + // In phần thành tích học tập theo từng học sinh. private static void showntime() { for (var hocSinh : mDSHocSinh) { printlnAdv(format("%s", toUpperCaseAdv(hocSinh.getThongTinCaNhan().getHoTen()))); @@ -68,7 +68,7 @@ private static void showntime() { } } - // Check out + // Cho phép nhập một danh sách học sinh mới trong cùng phiên chạy. private static void checkOut() { if (credit() == 1) { run(); diff --git a/quan_ly_hoc_sinh/ThanhTichHocTap.java b/quan_ly_hoc_sinh/ThanhTichHocTap.java index 218e3ce..06e6281 100644 --- a/quan_ly_hoc_sinh/ThanhTichHocTap.java +++ b/quan_ly_hoc_sinh/ThanhTichHocTap.java @@ -3,16 +3,19 @@ import static java.lang.String.*; import static yan_service.YANService.*; +/** + * Tóm tắt: Tổng hợp kết quả hai học kỳ của học sinh để xác định hạnh kiểm, + * điểm trung bình và xếp loại học lực cả năm. + */ public class ThanhTichHocTap { - // #region Fields + // Hai học kỳ đầu vào và các kết quả cả năm được tính sau khi nhập. private TheoKy hocKy1; private TheoKy hocKy2; private String hanhKiemCN; private double diemTrungBinhCN; private String xepLoaiCN; - // #endregion - // #region Methods + // Xét hạnh kiểm cả năm theo cặp hạnh kiểm học kỳ 1 và học kỳ 2. public void xetHanhKiemCN() { var hk1 = hocKy1.getHanhKiem(); var hk2 = hocKy2.getHanhKiem(); @@ -124,6 +127,7 @@ public void xetHanhKiemCN() { } } + // Điểm trung bình cả năm: học kỳ 2 nhân hệ số 2. public void tinhDiemTrungBinhCN() { try { diemTrungBinhCN = (hocKy1.getDiemTrungBinhTCCM() + hocKy2.getDiemTrungBinhTCCM() * 2) / 3; @@ -132,6 +136,7 @@ public void tinhDiemTrungBinhCN() { } } + // Xếp loại học lực cả năm từ điểm trung bình đã tính. public void xepLoaiHocLucCN() { if (diemTrungBinhCN >= 9) { xepLoaiCN = "Xuất Sắc"; @@ -193,9 +198,8 @@ public void xuatThanhTichHocTap() { xuatDiemTrungBinhCN(); xuatXepLoaiHocLucCN(); } - // #endregion - // #region Properties + // Getter/setter cho hai học kỳ; các kết quả cả năm được giữ chỉ đọc. public TheoKy getHocKy1() { return hocKy1; } @@ -235,5 +239,4 @@ public String getXepLoaiCN() { // public void setXepLoaiCN(String xepLoaiCN) { // this.xepLoaiCN = xepLoaiCN; // } - // #endregion } diff --git a/quan_ly_hoc_sinh/TheoKy.java b/quan_ly_hoc_sinh/TheoKy.java index 5e00ef8..599c9d8 100644 --- a/quan_ly_hoc_sinh/TheoKy.java +++ b/quan_ly_hoc_sinh/TheoKy.java @@ -4,8 +4,12 @@ import static yan_service.YANConstant.*; import static yan_service.YANService.*; +/** + * Tóm tắt: Quản lý điểm, hạnh kiểm, điểm trung bình và xếp loại của một học + * kỳ theo danh sách môn học cố định. + */ public class TheoKy { - // #region Fiedlds + // Các field đặt tên theo môn giúp code gọi ra từng môn cụ thể khi cần. private DiemTungMon monToan; private DiemTungMon monLy; private DiemTungMon monHoa; @@ -24,6 +28,8 @@ public class TheoKy { private String hanhKiem; private double diemTrungBinhTCCM; private String xepLoai; + + // Mảng giúp lặp nhập/xuất điểm cho toàn bộ môn mà không phải viết lặp tay. private final DiemTungMon[] mDiemTungMons = { monToan, monLy, @@ -58,11 +64,11 @@ public class TheoKy { "Nghệ Thuật", "Tự Chọn" }; - // #endregion - // #region Methods + // Tính trung bình tất cả các môn, trong đó Toán và Văn nhân hệ số 2. public void tinhDiemTrungBinhTCCM() { try { + diemTrungBinhTCCM = 0; for (int i = 0; i < mDiemTungMons.length; i++) { var dtbMon = mMonHocs[i].equals("Toán") || mMonHocs[i].equals("Văn") ? mDiemTungMons[i].getDiemTrungBinhMon() * 2 @@ -75,6 +81,7 @@ public void tinhDiemTrungBinhTCCM() { } } + // Xếp loại học lực học kỳ từ điểm trung bình các môn. public void xepLoaiHocLuc() { if (diemTrungBinhTCCM >= 9) { xepLoai = "Xuất Sắc"; @@ -91,6 +98,7 @@ public void xepLoaiHocLuc() { } } + // Nhập hạnh kiểm bằng menu để giá trị luôn nằm trong nhóm cho phép. public void nhapHanhKiem(int hocKy) { printlnAdv(RESET, format("Hạnh kiểm học kỳ %d", hocKy)); printlnAdv("1. Tốt "); @@ -120,8 +128,9 @@ public void nhapHanhKiem(int hocKy) { public void nhapDiemCacMon(int hocKy) { for (int i = 0; i < mDiemTungMons.length; i++) { - mDiemTungMons[i] = new DiemTungMon(); - mDiemTungMons[i].nhapDiemTungMon(mMonHocs[i], hocKy); + var diemTungMon = new DiemTungMon(); + diemTungMon.nhapDiemTungMon(mMonHocs[i], hocKy); + ganDiemTheoViTri(i, diemTungMon); } } @@ -157,15 +166,68 @@ public void xuatTheoKy(int hocKy) { xuatDiemTrungBinhTCCM(hocKy); xuatXepLoai(hocKy); } - // #endregion - // #region Properties + // Đồng bộ mảng môn học với các field đặt tên riêng để getter/setter không lệch dữ liệu. + private void ganDiemTheoViTri(int viTri, DiemTungMon diemTungMon) { + mDiemTungMons[viTri] = diemTungMon; + switch (viTri) { + case 0: + monToan = diemTungMon; + break; + case 1: + monLy = diemTungMon; + break; + case 2: + monHoa = diemTungMon; + break; + case 3: + monSinh = diemTungMon; + break; + case 4: + monVan = diemTungMon; + break; + case 5: + monAnh = diemTungMon; + break; + case 6: + monSu = diemTungMon; + break; + case 7: + monDia = diemTungMon; + break; + case 8: + monTin = diemTungMon; + break; + case 9: + monCongNghe = diemTungMon; + break; + case 10: + monGDCD = diemTungMon; + break; + case 11: + monTheDuc = diemTungMon; + break; + case 12: + monQuocPhong = diemTungMon; + break; + case 13: + monNgheThuat = diemTungMon; + break; + case 14: + monTuChon = diemTungMon; + break; + default: + break; + } + } + + // Getter/setter cho từng môn; setter luôn cập nhật cả mảng lặp. public DiemTungMon getMonToan() { return monToan; } public void setMonToan(DiemTungMon monToan) { - this.monToan = monToan; + ganDiemTheoViTri(0, monToan); } public DiemTungMon getMonLy() { @@ -173,7 +235,7 @@ public DiemTungMon getMonLy() { } public void setMonLy(DiemTungMon monLy) { - this.monLy = monLy; + ganDiemTheoViTri(1, monLy); } public DiemTungMon getMonHoa() { @@ -181,7 +243,7 @@ public DiemTungMon getMonHoa() { } public void setMonHoa(DiemTungMon monHoa) { - this.monHoa = monHoa; + ganDiemTheoViTri(2, monHoa); } public DiemTungMon getMonSinh() { @@ -189,7 +251,7 @@ public DiemTungMon getMonSinh() { } public void setMonSinh(DiemTungMon monSinh) { - this.monSinh = monSinh; + ganDiemTheoViTri(3, monSinh); } public DiemTungMon getMonVan() { @@ -197,7 +259,7 @@ public DiemTungMon getMonVan() { } public void setMonVan(DiemTungMon monVan) { - this.monVan = monVan; + ganDiemTheoViTri(4, monVan); } public DiemTungMon getMonAnh() { @@ -205,7 +267,7 @@ public DiemTungMon getMonAnh() { } public void setMonAnh(DiemTungMon monAnh) { - this.monAnh = monAnh; + ganDiemTheoViTri(5, monAnh); } public DiemTungMon getMonSu() { @@ -213,7 +275,7 @@ public DiemTungMon getMonSu() { } public void setMonSu(DiemTungMon monSu) { - this.monSu = monSu; + ganDiemTheoViTri(6, monSu); } public DiemTungMon getMonDia() { @@ -221,7 +283,7 @@ public DiemTungMon getMonDia() { } public void setMonDia(DiemTungMon monDia) { - this.monDia = monDia; + ganDiemTheoViTri(7, monDia); } public DiemTungMon getMonTin() { @@ -229,7 +291,7 @@ public DiemTungMon getMonTin() { } public void setMonTin(DiemTungMon monTin) { - this.monTin = monTin; + ganDiemTheoViTri(8, monTin); } public DiemTungMon getMonCongNghe() { @@ -237,7 +299,7 @@ public DiemTungMon getMonCongNghe() { } public void setMonCongNghe(DiemTungMon monCongNghe) { - this.monCongNghe = monCongNghe; + ganDiemTheoViTri(9, monCongNghe); } public DiemTungMon getMonGDCD() { @@ -245,7 +307,7 @@ public DiemTungMon getMonGDCD() { } public void setMonGDCD(DiemTungMon monGDCD) { - this.monGDCD = monGDCD; + ganDiemTheoViTri(10, monGDCD); } public DiemTungMon getMonTheDuc() { @@ -253,7 +315,7 @@ public DiemTungMon getMonTheDuc() { } public void setMonTheDuc(DiemTungMon monTheDuc) { - this.monTheDuc = monTheDuc; + ganDiemTheoViTri(11, monTheDuc); } public DiemTungMon getMonQuocPhong() { @@ -261,7 +323,7 @@ public DiemTungMon getMonQuocPhong() { } public void setMonQuocPhong(DiemTungMon monQuocPhong) { - this.monQuocPhong = monQuocPhong; + ganDiemTheoViTri(12, monQuocPhong); } public DiemTungMon getMonNgheThuat() { @@ -269,7 +331,7 @@ public DiemTungMon getMonNgheThuat() { } public void setMonNgheThuat(DiemTungMon monNgheThuat) { - this.monNgheThuat = monNgheThuat; + ganDiemTheoViTri(13, monNgheThuat); } public DiemTungMon getMonTuChon() { @@ -277,7 +339,7 @@ public DiemTungMon getMonTuChon() { } public void setMonTuChon(DiemTungMon monTuChon) { - this.monTuChon = monTuChon; + ganDiemTheoViTri(14, monTuChon); } public String getHanhKiem() { @@ -303,5 +365,4 @@ public String getXepLoai() { // public void setXepLoai(String xepLoai) { // this.xepLoai = xepLoai; // } - // #endregion } diff --git a/quan_ly_hoc_sinh/ThongTinCaNhan.java b/quan_ly_hoc_sinh/ThongTinCaNhan.java index 11dda0e..dc41ca9 100644 --- a/quan_ly_hoc_sinh/ThongTinCaNhan.java +++ b/quan_ly_hoc_sinh/ThongTinCaNhan.java @@ -7,8 +7,12 @@ import static yan_service.YANConstant.*; import static yan_service.YANService.*; +/** + * Tóm tắt: Quản lý thông tin nhận diện và liên hệ của học sinh như họ tên, + * ngày sinh, địa chỉ, số điện thoại, email và người liên hệ khẩn cấp. + */ public class ThongTinCaNhan { - // #region Fields + // Các trường thông tin cá nhân được nhập trực tiếp từ người dùng. private String hoTen; private String gioiTinh; private Date ngaySinh; @@ -21,9 +25,8 @@ public class ThongTinCaNhan { private String lienHeKhanCap; private String thuDienTu; private final Scanner mScan = new Scanner(in); - // #endregion - // #region Methods + // Nhóm hàm nhập từng trường giúp dễ tái sử dụng khi cần nhập lại một phần. public void nhapHoTen() { printAdv(GREEN, "Họ tên: ", RESET); hoTen = mScan.nextLine(); @@ -75,7 +78,7 @@ public void nhapLienHeKhanCap() { } public void nhapThuDienTu() { - printAdv(GREEN, "Thủ điện tử: ", RESET); + printAdv(GREEN, "Thư điện tử: ", RESET); thuDienTu = mScan.nextLine(); } @@ -134,7 +137,7 @@ public void xuatLienHeKhanCap() { } public void xuatThuDienTu() { - printlnAdv(format("Thủ điện tử: %s", thuDienTu)); + printlnAdv(format("Thư điện tử: %s", thuDienTu)); } public void xuatThongTinCaNhan() { @@ -150,9 +153,8 @@ public void xuatThongTinCaNhan() { xuatLienHeKhanCap(); xuatThuDienTu(); } - // #endregion - // #region Properties + // Getter/setter phục vụ các lớp tổng hợp thông tin học sinh. public String getHoTen() { return hoTen; } @@ -240,5 +242,4 @@ public String getThuDienTu() { public void setThuDienTu(String thuDienTu) { this.thuDienTu = thuDienTu; } - // #endregion } diff --git a/quan_ly_hoc_sinh/ThongTinCoBan.java b/quan_ly_hoc_sinh/ThongTinCoBan.java index b1d8996..b23e664 100644 --- a/quan_ly_hoc_sinh/ThongTinCoBan.java +++ b/quan_ly_hoc_sinh/ThongTinCoBan.java @@ -7,8 +7,12 @@ import static yan_service.YANConstant.*; import static yan_service.YANService.*; +/** + * Tóm tắt: Lưu thông tin học tập cơ bản của học sinh như trường, ban, khối, + * lớp, hoạt động tham gia và thông tin bảo hiểm y tế. + */ public class ThongTinCoBan { - // #region Fields + // Thông tin trường/lớp và bảo hiểm đi kèm hồ sơ học sinh. private String tenTruong; private String tenBan; private String tenKhoi; @@ -16,9 +20,8 @@ public class ThongTinCoBan { private String thamGiaHoatDong; private BaoHiemYTe baoHiemYTe; private final Scanner mScan = new Scanner(in); - // #endregion - // #region Methods + // Nhóm hàm nhập từng trường cơ bản. public void nhapTenTruong() { printAdv(GREEN, "Tên trường: ", RESET); tenTruong = mScan.nextLine(); @@ -90,9 +93,8 @@ public void xuatThongTinCoBan() { xuatThamGiaHoatDong(); xuatBaoHiemYTe(); } - // #endregion - // #region Properties + // Getter/setter phục vụ truy cập dữ liệu từ lớp HocSinh. public String getTenTruong() { return tenTruong; } @@ -140,5 +142,4 @@ public BaoHiemYTe getBaoHiemYTe() { public void setBaoHiemYTe(BaoHiemYTe baoHiemYTe) { this.baoHiemYTe = baoHiemYTe; } - // #endregion } diff --git a/quan_ly_nhan_su/GiamDoc.java b/quan_ly_nhan_su/GiamDoc.java index 40c36fe..b0e2e08 100644 --- a/quan_ly_nhan_su/GiamDoc.java +++ b/quan_ly_nhan_su/GiamDoc.java @@ -1,27 +1,36 @@ package quan_ly_nhan_su; -import static java.lang.Double.*; -import static java.lang.String.*; -import static yan_service.YANConstant.*; -import static yan_service.YANService.*; +import static java.lang.String.format; +import static yan_service.YANConstant.GREEN; +import static yan_service.YANConstant.RESET; +import static yan_service.YANService.numLimit; +import static yan_service.YANService.printAdv; +import static yan_service.YANService.printlnAdv; +import static yan_service.YANService.writePerfectDub; +/** + * Tóm tắt: Giám đốc có lương ngày 300, nắm giữ phần trăm cổ phần không vượt + * quá 100% và có thu nhập bằng lương cộng phần lợi nhuận tương ứng. + */ public class GiamDoc extends NhanSu { - // #region Fields + private static final double LUONG_NGAY = 300; + private double coPhan; private double thuNhap; - private final String CHUC_VU = "giám đốc"; - private final double LUONG_NGAY = 300; - // #endregion - // #region Methods @Override - public void tinhLuong() { - luongThang = soNgayLamViec * LUONG_NGAY; + protected double getLuongNgay() { + return LUONG_NGAY; + } + + @Override + public String getChucVu() { + return "giám đốc"; } public void nhapCoPhan() { - printAdv(GREEN, "Cổ phần: ", RESET); - coPhan = numLimit(0, MAX_VALUE); + printAdv(GREEN, "Cổ phần (%): ", RESET); + coPhan = numLimit(0d, 100d); } @Override @@ -39,34 +48,21 @@ public void xuatThuNhap() { printlnAdv(format("Thu nhập: %,.0f", thuNhap)); } - @Override - public void xuatChucVu() { - printlnAdv(format("Chức vụ: %s", CHUC_VU)); - } - - @Override - public void xuatLuongThang() { - printlnAdv(format("Lương tháng: %,.0f", luongThang)); - } - @Override public void xuatNhanSu() { - super.xuatMaNhanVien(); - super.xuatHoTen(); - super.xuatSoDienThoai(); - xuatChucVu(); + xuatThongTinChung(); xuatCoPhan(); - super.xuatSoNgayLamViec(); xuatLuongThang(); } - // #endregion - // #region Properties public double getCoPhan() { return coPhan; } public void setCoPhan(double coPhan) { + if (coPhan < 0 || coPhan > 100) { + throw new IllegalArgumentException("Cổ phần giám đốc phải nằm trong khoảng 0-100%."); + } this.coPhan = coPhan; } @@ -77,5 +73,4 @@ public double getThuNhap() { public void setThuNhap(double thuNhap) { this.thuNhap = thuNhap; } - // #endregion } diff --git a/quan_ly_nhan_su/NhanSu.java b/quan_ly_nhan_su/NhanSu.java index 91fca48..d651b30 100644 --- a/quan_ly_nhan_su/NhanSu.java +++ b/quan_ly_nhan_su/NhanSu.java @@ -1,41 +1,60 @@ package quan_ly_nhan_su; -import java.util.*; - -import static java.lang.String.*; -import static java.lang.System.*; -import static yan_service.YANConstant.*; -import static yan_service.YANService.*; - -public class NhanSu { - // #region Fields - private String maNhanVien; - private String hoTen; - private String soDienThoai; +import java.util.Scanner; + +import static java.lang.String.format; +import static java.lang.System.in; +import static yan_service.YANConstant.GREEN; +import static yan_service.YANConstant.RESET; +import static yan_service.YANService.numLimit; +import static yan_service.YANService.printAdv; +import static yan_service.YANService.printlnAdv; +import static yan_service.YANService.writePerfectDub; + +/** + * Tóm tắt: Lớp nền cho mọi nhân sự trong công ty, gom thông tin chung như mã, + * họ tên, số điện thoại, số ngày làm việc và lương tháng. + */ +public abstract class NhanSu { + // Dùng chung một Scanner để tránh xung đột khi nhiều đối tượng cùng đọc System.in. + protected static final Scanner SCANNER = new Scanner(in); + + private String maNhanVien = ""; + private String hoTen = ""; + private String soDienThoai = ""; protected double soNgayLamViec; protected double luongThang; - private final String CHUC_VU = "nhân viên"; - private final Scanner mScan = new Scanner(in); - // #endregion - // #region Methods + /** + * Tóm tắt: Trả về lương một ngày theo từng chức vụ cụ thể. + */ + protected abstract double getLuongNgay(); + + /** + * Tóm tắt: Trả về tên chức vụ để in ra màn hình. + */ + public abstract String getChucVu(); + + /** + * Tóm tắt: Công thức mặc định là số ngày làm việc nhân lương ngày. + */ public void tinhLuong() { - luongThang = 0; + luongThang = soNgayLamViec * getLuongNgay(); } public void nhapMaNhanVien() { printAdv(GREEN, "Mã nhân viên: ", RESET); - maNhanVien = mScan.nextLine(); + maNhanVien = SCANNER.nextLine().trim(); } public void nhapHoTen() { printAdv(GREEN, "Họ tên: ", RESET); - hoTen = mScan.nextLine(); + hoTen = SCANNER.nextLine().trim(); } public void nhapSoDienThoai() { printAdv(GREEN, "Số điện thoại: ", RESET); - soDienThoai = mScan.nextLine(); + soDienThoai = SCANNER.nextLine().trim(); } public void nhapSoNgayLamViec() { @@ -43,10 +62,14 @@ public void nhapSoNgayLamViec() { soNgayLamViec = numLimit(0d, 31d); } + /** + * Tóm tắt: Nhập các trường chung rồi tính lại lương theo chức vụ hiện tại. + */ public void nhapNhanSu() { nhapHoTen(); nhapSoDienThoai(); nhapSoNgayLamViec(); + tinhLuong(); } public void xuatMaNhanVien() { @@ -62,7 +85,11 @@ public void xuatSoDienThoai() { } public void xuatChucVu() { - printlnAdv(format("Chức vụ: %s", CHUC_VU)); + printlnAdv(format("Chức vụ: %s", getChucVu())); + } + + public void xuatLuongNgay() { + printlnAdv(format("Lương một ngày: %s", writePerfectDub(getLuongNgay()))); } public void xuatSoNgayLamViec() { @@ -73,22 +100,29 @@ public void xuatLuongThang() { printlnAdv(format("Lương tháng: %,.0f", luongThang)); } - public void xuatNhanSu() { + /** + * Tóm tắt: In phần thông tin chung, các lớp con sẽ bổ sung thuộc tính riêng. + */ + protected void xuatThongTinChung() { xuatMaNhanVien(); xuatHoTen(); xuatSoDienThoai(); xuatChucVu(); + xuatLuongNgay(); xuatSoNgayLamViec(); } - // #endregion - // #region Properties + public void xuatNhanSu() { + xuatThongTinChung(); + xuatLuongThang(); + } + public String getMaNhanVien() { return maNhanVien; } public void setMaNhanVien(String maNhanVien) { - this.maNhanVien = maNhanVien; + this.maNhanVien = maNhanVien == null ? "" : maNhanVien.trim(); } public String getHoTen() { @@ -96,7 +130,7 @@ public String getHoTen() { } public void setHoTen(String hoTen) { - this.hoTen = hoTen; + this.hoTen = hoTen == null ? "" : hoTen.trim(); } public String getSoDienThoai() { @@ -104,7 +138,7 @@ public String getSoDienThoai() { } public void setSoDienThoai(String soDienThoai) { - this.soDienThoai = soDienThoai; + this.soDienThoai = soDienThoai == null ? "" : soDienThoai.trim(); } public double getSoNgayLamViec() { @@ -113,14 +147,10 @@ public double getSoNgayLamViec() { public void setSoNgayLamViec(double soNgayLamViec) { this.soNgayLamViec = soNgayLamViec; + tinhLuong(); } public double getLuongThang() { return luongThang; } - - // public void setLuongThang(double luongThang) { - // this.luongThang = luongThang; - // } - // #endregion } diff --git a/quan_ly_nhan_su/NhanVien.java b/quan_ly_nhan_su/NhanVien.java index 6b2833c..63e16e7 100644 --- a/quan_ly_nhan_su/NhanVien.java +++ b/quan_ly_nhan_su/NhanVien.java @@ -1,65 +1,46 @@ package quan_ly_nhan_su; -import java.util.*; - -import static java.lang.String.*; -import static java.lang.System.*; -import static yan_service.YANConstant.*; -import static yan_service.YANService.*; +import static java.lang.String.format; +import static yan_service.YANService.printlnAdv; +/** + * Tóm tắt: Nhân viên thường có lương ngày 100 và có thể được phân bổ cho một + * trưởng phòng; nếu chưa phân bổ thì trưởng phòng quản lý là null. + */ public class NhanVien extends NhanSu { - // #region Fields - private String tenTruongPhong; - private final double LUONG_NGAY = 100; - private final Scanner mScan = new Scanner(in); - // #endregion + private static final double LUONG_NGAY = 100; - // #region Methods - @Override - public void tinhLuong() { - luongThang = soNgayLamViec * LUONG_NGAY; - } - - public void nhapTenTruongPhong() { - printAdv(GREEN, "Tên trưởng phòng: ", RESET); - tenTruongPhong = mScan.nextLine(); - } + private TruongPhong truongPhongQuanLy; @Override - public void nhapNhanSu() { - super.nhapNhanSu(); - nhapTenTruongPhong(); - tinhLuong(); + protected double getLuongNgay() { + return LUONG_NGAY; } - public void xuatTenTruongPhong() { - printlnAdv(format("Tên trưởng phòng: %s", tenTruongPhong)); + @Override + public String getChucVu() { + return "nhân viên"; } - @Override - public void xuatLuongThang() { - printlnAdv(format("Lương tháng: %,.0f", luongThang)); + public void xuatTruongPhongQuanLy() { + var thongTinTruongPhong = truongPhongQuanLy == null + ? "null" + : format("%s (%s)", truongPhongQuanLy.getHoTen(), truongPhongQuanLy.getMaNhanVien()); + printlnAdv(format("Trưởng phòng quản lý: %s", thongTinTruongPhong)); } @Override public void xuatNhanSu() { - super.xuatMaNhanVien(); - super.xuatHoTen(); - super.xuatSoDienThoai(); - super.xuatChucVu(); - xuatTenTruongPhong(); - super.xuatSoNgayLamViec(); + xuatThongTinChung(); + xuatTruongPhongQuanLy(); xuatLuongThang(); } - // #endregion - // #region Properties - public String getTenTruongPhong() { - return tenTruongPhong; + public TruongPhong getTruongPhongQuanLy() { + return truongPhongQuanLy; } - public void setTenTruongPhong(String tenTruongPhong) { - this.tenTruongPhong = tenTruongPhong; + public void setTruongPhongQuanLy(TruongPhong truongPhongQuanLy) { + this.truongPhongQuanLy = truongPhongQuanLy; } - // #endregion } diff --git a/quan_ly_nhan_su/QuanLyNhanSu.java b/quan_ly_nhan_su/QuanLyNhanSu.java index 8bb2651..664df4b 100644 --- a/quan_ly_nhan_su/QuanLyNhanSu.java +++ b/quan_ly_nhan_su/QuanLyNhanSu.java @@ -1,312 +1,331 @@ package quan_ly_nhan_su; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; -import static java.lang.Integer.*; -import static java.lang.String.*; -import static java.lang.System.*; -import static java.util.Collections.reverse; -import static quan_ly_nhan_su.Service.*; -import static yan_service.YANConstant.*; -import static yan_service.YANService.*; +import static java.lang.String.format; +import static java.lang.System.in; +import static java.lang.System.out; +import static quan_ly_nhan_su.Service.addNewbie; +import static quan_ly_nhan_su.Service.allInGiamDoc; +import static quan_ly_nhan_su.Service.capNhatLuongVaQuanLy; +import static quan_ly_nhan_su.Service.layDanhSachNhanVien; +import static quan_ly_nhan_su.Service.layDanhSachTruongPhong; +import static quan_ly_nhan_su.Service.phanBoNhanVien; +import static quan_ly_nhan_su.Service.sortByName; +import static quan_ly_nhan_su.Service.sortBySalaryDesc; +import static quan_ly_nhan_su.Service.sumSalary; +import static quan_ly_nhan_su.Service.topSalaryNhanVien; +import static quan_ly_nhan_su.Service.topShare; +import static quan_ly_nhan_su.Service.topTeam; +import static quan_ly_nhan_su.Service.xoaNhanSu; +import static yan_service.YANConstant.BLUE_BOLD; +import static yan_service.YANConstant.CYAN; +import static yan_service.YANConstant.GREEN; +import static yan_service.YANConstant.RED; +import static yan_service.YANConstant.RESET; +import static yan_service.YANConstant.YELLOW; +import static yan_service.YANService.credit; +import static yan_service.YANService.isNullOrWhitespace; +import static yan_service.YANService.numLimit; +import static yan_service.YANService.printAdv; +import static yan_service.YANService.printlnAdv; +import static yan_service.YANService.toTitleCaseAdv; +import static yan_service.YANService.writePerfectDub; +/** + * Tóm tắt: Chương trình console quản lý nhân sự theo đúng menu trong README: + * nhập công ty, phân bổ nhân viên, thêm/xóa, thống kê lương và thu nhập. + */ public class QuanLyNhanSu { + private static final Scanner SCANNER = new Scanner(in); + + private static String mTenCongTy = ""; + private static String mMaSoThue = ""; + private static double mDoanhThuThang; + private static final List mDSNhanSu = new ArrayList(); + public static void main(String[] args) { - // tit out.println(BLUE_BOLD); printlnAdv("Bài Tập Quản Lý Nhân Sự"); - // input - out.println(); - printAdv(GREEN, "Nhập vào số thành viên: ", RESET); - var n = numLimit(1, MAX_VALUE); - printAdv(GREEN, "Tên công ty: ", RESET); - mTenCongTy = mScan.nextLine(); - printAdv(GREEN, "Mã số thuế: ", RESET); - mMaSoThue = mScan.nextLine(); - printAdv(GREEN, "Doanh thu tháng: ", RESET); - mDoanhThuThang = numLimit(Double.MIN_VALUE, Double.MAX_VALUE); - mDSNhanSu = new ArrayList(); - for (var i = 0; i < n; i++) { - out.println(); - printlnAdv(CYAN, format("Thành viên thứ %d", i + 1)); - mDSNhanSu.add(addNewbie(mDSNhanSu)); - } - // process - checkTeamLead(mDSNhanSu); - memberEachTeam(mDSNhanSu); - // content - run(); + do { + run(); + } while (credit() == 1); } - // Fields - private static final Scanner mScan = new Scanner(in); - private static String mTenCongTy; - private static String mMaSoThue; - private static double mDoanhThuThang; - private static List mDSNhanSu; - - // Main + /** + * Tóm tắt: Hiển thị menu chính đúng thứ tự yêu cầu và điều phối chức năng. + */ private static void run() { - // output out.println(CYAN); - printlnAdv(" 1. Bổ nhiệm nhân viên làm trưởng phòng"); - printlnAdv(" 2. Thêm nhân sự "); - printlnAdv(" 3. Xóa nhân sự "); - printlnAdv(" 4. Xuất thông tin toàn bộ công ty "); - printlnAdv(" 5. Tính tổng lương toàn công ty "); - printlnAdv(" 6. Tìm thành viên có lương cao nhất "); - printlnAdv(" 7. Tìm trưởng phòng quản lý nhiều nhất"); - printlnAdv(" 8. Sắp xếp nhân sự theo tên "); - printlnAdv(" 9. Sắp xếp nhân sự giảm dần "); - printlnAdv("10. Tìm giám đốc có cổ phần nhiều nhất "); - printlnAdv("11. Tính tổng thu nhập của mỗi giám đốc"); + printlnAdv(" 1. Nhập thông tin công ty "); + printlnAdv(" 2. Phân bổ Nhân viên vào Trưởng phòng "); + printlnAdv(" 3. Thêm, xóa thông tin một nhân sự "); + printlnAdv(" 4. Xuất ra thông tin toàn bộ người trong công ty "); + printlnAdv(" 5. Tính và xuất tổng lương cho toàn công ty "); + printlnAdv(" 6. Tìm Nhân viên thường có lương cao nhất "); + printlnAdv(" 7. Tìm Trưởng Phòng có nhiều nhân viên nhất "); + printlnAdv(" 8. Sắp xếp nhân viên toàn công ty theo thứ tự abc"); + printlnAdv(" 9. Sắp xếp nhân viên toàn công ty theo lương giảm"); + printlnAdv("10. Tìm Giám Đốc có số lượng cổ phần nhiều nhất "); + printlnAdv("11. Tính và Xuất tổng THU NHẬP từng Giám Đốc "); printAdv("Chọn 1 trong các phương án trên: "); out.print(RESET); + switch (numLimit(1, 11)) { - case 1: { - unitA(); + case 1: + nhapThongTinCongTy(); + break; + case 2: + phanBoNhanVienVaoTruongPhong(); break; - } - case 2: { - unitB(); + case 3: + themHoacXoaNhanSu(); break; - } - case 3: { - unitC(); + case 4: + xuatToanBoNhanSu(); break; - } - case 4: { - unitD(); + case 5: + xuatTongLuong(); break; - } - case 5: { - unitE(); + case 6: + timNhanVienLuongCaoNhat(); break; - } - case 6: { - unitF(); + case 7: + timTruongPhongQuanLyNhieuNhat(); break; - } - case 7: { - unitG(); + case 8: + sapXepTheoTen(); break; - } - case 8: { - unitH(); + case 9: + sapXepTheoLuongGiamDan(); break; - } - case 9: { - unitI(); + case 10: + timGiamDocCoPhanCaoNhat(); break; - } - case 10: { - unitJ(); + case 11: + xuatThuNhapGiamDoc(); break; - } - case 11: { - unitK(); + default: + printlnAdv(RED, "Chức năng không hợp lệ."); break; - } } - // ctrl - checkOut(); } - // Unit 1 - private static void unitA() { - // split nhanvien - var dsNhanVien = new ArrayList(); - for (var nhanSu : mDSNhanSu) { - if (nhanSu instanceof NhanVien) { - dsNhanVien.add((NhanVien) nhanSu); - } + private static void nhapThongTinCongTy() { + out.println(); + printAdv(GREEN, "Tên công ty: ", RESET); + mTenCongTy = SCANNER.nextLine().trim(); + printAdv(GREEN, "Mã số thuế: ", RESET); + mMaSoThue = SCANNER.nextLine().trim(); + printAdv(GREEN, "Doanh thu tháng: ", RESET); + mDoanhThuThang = numLimit(0d, Double.MAX_VALUE); + checkIn(); + } + + private static void phanBoNhanVienVaoTruongPhong() { + if (!coNhanSuHayThongBao()) { + return; } - var max = dsNhanVien.size(); - if (max > 0) { - // cap - out.println(RESET); - printlnAdv("Danh sách nhân viên"); - for (var i = 0; i < max; i++) { - var nhanVien = dsNhanVien.get(i); - printlnAdv(format("%d. %s (%s)", i + 1, nhanVien.getHoTen(), nhanVien.getMaNhanVien())); - } - printAdv("Chọn 1 trong các phương án trên: "); - // main - var index = findIndexByCode(mDSNhanSu, dsNhanVien.get(numLimit(1, max) - 1).getMaNhanVien()); - mDSNhanSu.add(index, nhanVienTransToTruongPhong(mDSNhanSu.get(index))); - mDSNhanSu.remove(index + 1); - // finish - memberEachTeam(mDSNhanSu); - unitD(); - } else { - checkIn(); - printlnAdv("Công ty không có nhân viên nào!"); - out.println(); + + var dsNhanVien = layDanhSachNhanVien(mDSNhanSu); + var dsTruongPhong = layDanhSachTruongPhong(mDSNhanSu); + if (dsNhanVien.isEmpty() || dsTruongPhong.isEmpty()) { + printlnAdv(RED, "Cần có ít nhất một nhân viên thường và một trưởng phòng."); + return; } + + out.println(RESET); + printlnAdv("Danh sách nhân viên thường"); + xuatDanhSachRutGon(dsNhanVien); + printAdv("Chọn nhân viên cần phân bổ: "); + var nhanVien = dsNhanVien.get(numLimit(1, dsNhanVien.size()) - 1); + + out.println(); + printlnAdv("0. Bỏ phân bổ trưởng phòng"); + xuatDanhSachRutGon(dsTruongPhong); + printAdv("Chọn trưởng phòng quản lý: "); + var luaChonTruongPhong = numLimit(0, dsTruongPhong.size()); + var truongPhong = luaChonTruongPhong == 0 ? null : dsTruongPhong.get(luaChonTruongPhong - 1); + + phanBoNhanVien(nhanVien, truongPhong); + capNhatLuongVaQuanLy(mDSNhanSu); + printlnAdv(GREEN, "Đã cập nhật phân bổ nhân sự.", RESET); } - // Unit 2 - private static void unitB() { - // cap + private static void themHoacXoaNhanSu() { out.println(CYAN); - printlnAdv("Thêm thành viên mới"); - // main - mDSNhanSu.add(addNewbie(mDSNhanSu)); - // finish - memberEachTeam(mDSNhanSu); - unitD(); + printlnAdv("1. Thêm nhân sự"); + printlnAdv("2. Xóa nhân sự "); + printAdv("Chọn 1 trong các phương án trên: "); + switch (numLimit(1, 2)) { + case 1: + mDSNhanSu.add(addNewbie(mDSNhanSu)); + capNhatLuongVaQuanLy(mDSNhanSu); + printlnAdv(GREEN, "Đã thêm nhân sự mới.", RESET); + break; + case 2: + xoaNhanSuTheoLuaChon(); + break; + default: + break; + } } - // Unit 3 - private static void unitC() { - // cap - printlnAdv(RESET, "Danh sách nhân viên"); - var max = mDSNhanSu.size(); - for (var i = 0; i < max; i++) { - var nhanSu = mDSNhanSu.get(i); - printlnAdv(format("%d. %s (%s)", i + 1, nhanSu.getHoTen(), nhanSu.getMaNhanVien())); + private static void xoaNhanSuTheoLuaChon() { + if (!coNhanSuHayThongBao()) { + return; } - printAdv("Chọn 1 trong các phương án trên: "); - // main - var index = findIndexByCode(mDSNhanSu, mDSNhanSu.get(numLimit(1, max) - 1).getMaNhanVien()); - mDSNhanSu.remove(index); - // finish - checkTeamLead(mDSNhanSu); - memberEachTeam(mDSNhanSu); - unitD(); + + printlnAdv(RESET, "Danh sách nhân sự"); + xuatDanhSachRutGon(mDSNhanSu); + printAdv("Chọn nhân sự cần xóa: "); + var nhanSuCanXoa = mDSNhanSu.get(numLimit(1, mDSNhanSu.size()) - 1); + xoaNhanSu(mDSNhanSu, nhanSuCanXoa); + printlnAdv(GREEN, "Đã xóa nhân sự và đồng bộ liên kết quản lý.", RESET); } - // Unit 4 - private static void unitD() { - // cap + private static void xuatToanBoNhanSu() { + if (!coNhanSuHayThongBao()) { + return; + } + checkIn(); - // shown + capNhatLuongVaQuanLy(mDSNhanSu); for (var nhanSu : mDSNhanSu) { nhanSu.xuatNhanSu(); out.println(); } } - // Unit 5 - private static void unitE() { - // intro - unitD(); - // finish + private static void xuatTongLuong() { + if (!coNhanSuHayThongBao()) { + return; + } + + checkIn(); printlnAdv(format("Tổng lương toàn công ty: %,.0f", sumSalary(mDSNhanSu))); out.println(); } - // Unit 6 - private static void unitF() { - // cap + private static void timNhanVienLuongCaoNhat() { + var dsTopSalary = topSalaryNhanVien(mDSNhanSu); + if (dsTopSalary.isEmpty()) { + printlnAdv(RED, "Công ty chưa có nhân viên thường."); + return; + } + checkIn(); - printlnAdv("Thành viên lương cao nhất"); - out.println(); - // main - var dsTopSalary = topSalary(mDSNhanSu); - // shown - for (var topNhanSu : dsTopSalary) { - topNhanSu.xuatHoTen(); - topNhanSu.xuatChucVu(); - topNhanSu.xuatLuongThang(); + printlnAdv("Nhân viên thường có lương cao nhất"); + for (var nhanVien : dsTopSalary) { + nhanVien.xuatHoTen(); + nhanVien.xuatLuongThang(); out.println(); } } - // Unit 7 - private static void unitG() { - // cap - checkIn(); - printlnAdv("Trưởng phòng quản lý nhiều thành viên nhât"); - out.println(); - // main + private static void timTruongPhongQuanLyNhieuNhat() { var dsTopTeam = topTeam(mDSNhanSu); - // shown - for (var topTruongPhong : dsTopTeam) { - topTruongPhong.xuatHoTen(); - topTruongPhong.xuatSoThanhVien(); + if (dsTopTeam.isEmpty()) { + printlnAdv(RED, "Công ty chưa có trưởng phòng."); + return; + } + + checkIn(); + printlnAdv("Trưởng phòng quản lý nhiều nhân viên nhất"); + for (var truongPhong : dsTopTeam) { + truongPhong.xuatHoTen(); + truongPhong.xuatSoThanhVien(); out.println(); } } - // Unit 8 - private static void unitH() { - // cap - checkIn(); - printlnAdv("Sắp xếp nhân sự theo tên"); - out.println(); - // main + private static void sapXepTheoTen() { + if (!coNhanSuHayThongBao()) { + return; + } + var dsNhanSu = new ArrayList(mDSNhanSu); sortByName(dsNhanSu); - // shown - for (var nhanSu : dsNhanSu) { - nhanSu.xuatNhanSu(); - out.println(); + xuatDanhSachSauSapXep("Sắp xếp nhân sự theo thứ tự abc", dsNhanSu); + } + + private static void sapXepTheoLuongGiamDan() { + if (!coNhanSuHayThongBao()) { + return; } + + var dsNhanSu = new ArrayList(mDSNhanSu); + sortBySalaryDesc(dsNhanSu); + xuatDanhSachSauSapXep("Sắp xếp nhân sự theo lương giảm dần", dsNhanSu); } - // Unit 9 - private static void unitI() { - // cap + private static void timGiamDocCoPhanCaoNhat() { + var dsTopShare = topShare(mDSNhanSu); + if (dsTopShare.isEmpty()) { + printlnAdv(RED, "Công ty chưa có giám đốc."); + return; + } + checkIn(); - printlnAdv("Sắp xếp nhân sự giảm dần"); - out.println(); - // main - var dsNhanSu = new ArrayList(mDSNhanSu); - sortByCode(dsNhanSu); - reverse(dsNhanSu); - // shown - for (var nhanSu : dsNhanSu) { - nhanSu.xuatNhanSu(); + printlnAdv("Giám đốc có nhiều cổ phần nhất"); + for (var giamDoc : dsTopShare) { + giamDoc.xuatHoTen(); + giamDoc.xuatCoPhan(); out.println(); } } - // Unit 10 - private static void unitJ() { - // cap + private static void xuatThuNhapGiamDoc() { + var dsGiamDoc = allInGiamDoc(mDSNhanSu, mDoanhThuThang); + if (dsGiamDoc.isEmpty()) { + printlnAdv(RED, "Công ty chưa có giám đốc."); + return; + } + checkIn(); - printlnAdv("Giám đốc có nhiều cổ phần nhất"); - out.println(); - // main - var dsTopShare = topShare(mDSNhanSu); - // shown - for (var topGiamDoc : dsTopShare) { - topGiamDoc.xuatHoTen(); - topGiamDoc.xuatCoPhan(); + printlnAdv("Thu nhập giám đốc"); + for (var giamDoc : dsGiamDoc) { + giamDoc.xuatHoTen(); + giamDoc.xuatThuNhap(); out.println(); } } - // Unit 11 - private static void unitK() { - // cap + private static void xuatDanhSachSauSapXep(String tieuDe, List dsNhanSu) { checkIn(); - printlnAdv("Thu nhập giám đốc"); + printlnAdv(tieuDe); out.println(); - // main - var dsGiamDoc = allInGiamDoc(mDSNhanSu, mDoanhThuThang); - // shown - for (var topGiamDoc : dsGiamDoc) { - topGiamDoc.xuatHoTen(); - topGiamDoc.xuatThuNhap(); + for (var nhanSu : dsNhanSu) { + nhanSu.xuatNhanSu(); out.println(); } } - // Check in - private static void checkIn() { - out.println(YELLOW); - printlnAdv(format("Công ty %s", toTitleCaseAdv(mTenCongTy))); - printlnAdv(format("MST %s", mMaSoThue)); - printlnAdv(format("Doanh Thu Tháng %s", writePerfectDub(mDoanhThuThang))); - out.println(); + private static void xuatDanhSachRutGon(List dsNhanSu) { + for (var i = 0; i < dsNhanSu.size(); i++) { + var nhanSu = dsNhanSu.get(i); + printlnAdv(format("%d. %s - %s (%s)", i + 1, nhanSu.getHoTen(), nhanSu.getChucVu(), + nhanSu.getMaNhanVien())); + } } - // Check out - private static void checkOut() { - if (credit() == 1) { - run(); + private static boolean coNhanSuHayThongBao() { + if (mDSNhanSu.isEmpty()) { + printlnAdv(RED, "Công ty chưa có nhân sự."); + return false; } + return true; + } + + private static void checkIn() { + var tenCongTy = isNullOrWhitespace(mTenCongTy) ? "Chưa nhập" : toTitleCaseAdv(mTenCongTy); + var maSoThue = isNullOrWhitespace(mMaSoThue) ? "Chưa nhập" : mMaSoThue; + out.println(YELLOW); + printlnAdv(format("Công ty %s", tenCongTy)); + printlnAdv(format("MST %s", maSoThue)); + printlnAdv(format("Doanh thu tháng %s", writePerfectDub(mDoanhThuThang))); + out.println(); } } diff --git a/quan_ly_nhan_su/Service.java b/quan_ly_nhan_su/Service.java index 8ba546d..f78893c 100644 --- a/quan_ly_nhan_su/Service.java +++ b/quan_ly_nhan_su/Service.java @@ -1,13 +1,31 @@ package quan_ly_nhan_su; -import java.util.*; +import java.text.Collator; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; -import static java.util.Collections.*; -import static yan_service.YANConstant.*; -import static yan_service.YANService.*; +import static yan_service.YANConstant.RED; +import static yan_service.YANConstant.RESET; +import static yan_service.YANService.numLimit; +import static yan_service.YANService.printAdv; +import static yan_service.YANService.printlnAdv; +/** + * Tóm tắt: Tập hợp các nghiệp vụ xử lý danh sách nhân sự như thêm/xóa, phân bổ + * nhân viên vào trưởng phòng, tính lương và tìm kiếm theo yêu cầu README. + */ public class Service { - // Add new user + private static final Collator VIETNAMESE_COLLATOR = Collator.getInstance(new Locale("vi", "VN")); + + static { + VIETNAMESE_COLLATOR.setStrength(Collator.PRIMARY); + } + + /** + * Tóm tắt: Tạo nhân sự mới và buộc mã nhân viên không trùng trong công ty. + */ public static NhanSu addNewbie(List dsNhanSu) { var nhanSu = userType(); do { @@ -17,7 +35,9 @@ public static NhanSu addNewbie(List dsNhanSu) { return nhanSu; } - // Split user + /** + * Tóm tắt: Cho người dùng chọn đúng loại nhân sự sẽ được nhập. + */ public static NhanSu userType() { printlnAdv(RESET, "Vị trí trong công ty"); printlnAdv("1. Nhân viên "); @@ -25,98 +45,140 @@ public static NhanSu userType() { printlnAdv("3. Giám đốc "); printAdv("Chọn 1 trong các phương án trên: "); switch (numLimit(1, 3)) { - case 1: { + case 1: return new NhanVien(); - } - case 2: { + case 2: return new TruongPhong(); - } - case 3: { + case 3: return new GiamDoc(); - } - default: { - return new NhanSu(); - } + default: + throw new IllegalStateException("Loại nhân sự không hợp lệ."); } } - // Check regist + /** + * Tóm tắt: Kiểm tra trùng mã, bỏ qua khác biệt chữ hoa/thường. + */ public static boolean isRegist(List dsNhanSu, String maNhanVien) { - var isSuccess = false; for (var nhanSu : dsNhanSu) { - if (nhanSu.getMaNhanVien().equals(maNhanVien)) { + if (nhanSu.getMaNhanVien().equalsIgnoreCase(maNhanVien)) { printlnAdv(RED, "Mã nhân viên đã tồn tại!"); - isSuccess = true; - break; + return true; } } - return isSuccess; + return false; } - // Check team leader - public static void checkTeamLead(List dsNhanSu) { + /** + * Tóm tắt: Đồng bộ quan hệ quản lý và lương sau mỗi lần thêm, xóa hoặc phân bổ. + */ + public static void capNhatLuongVaQuanLy(List dsNhanSu) { + for (var nhanSu : dsNhanSu) { + if (nhanSu instanceof TruongPhong) { + ((TruongPhong) nhanSu).setSoThanhVien(0); + } + } + for (var nhanSu : dsNhanSu) { if (nhanSu instanceof NhanVien) { var nhanVien = (NhanVien) nhanSu; - var isSuccess = false; - for (var truongPhong : dsNhanSu) { - if (truongPhong instanceof TruongPhong - && nhanVien.getTenTruongPhong().equals(truongPhong.getHoTen())) { - isSuccess = true; - break; - } - } - if (!isSuccess) { - nhanVien.setTenTruongPhong(""); + var truongPhong = nhanVien.getTruongPhongQuanLy(); + if (truongPhong == null || !dsNhanSu.contains(truongPhong)) { + nhanVien.setTruongPhongQuanLy(null); + } else { + truongPhong.setSoThanhVien(truongPhong.getSoThanhVien() + 1); } } } + + for (var nhanSu : dsNhanSu) { + nhanSu.tinhLuong(); + } } - // Count member in team + /** + * Tóm tắt: Giữ lại tên hàm cũ để các đoạn gọi hiện có vẫn đọc dễ hiểu. + */ + public static void checkTeamLead(List dsNhanSu) { + capNhatLuongVaQuanLy(dsNhanSu); + } + + /** + * Tóm tắt: Giữ lại tên hàm cũ, thực chất hiện nay là đồng bộ lại số thành viên. + */ public static void memberEachTeam(List dsNhanSu) { - for (var nhanSu : dsNhanSu) { - if (nhanSu instanceof TruongPhong) { - var truongPhong = ((TruongPhong) nhanSu); - var count = 0; - for (var nhanVien : dsNhanSu) { - if (nhanVien instanceof NhanVien - && ((NhanVien) nhanVien).getTenTruongPhong().equals(truongPhong.getHoTen())) { - count++; + capNhatLuongVaQuanLy(dsNhanSu); + } + + public static void phanBoNhanVien(NhanVien nhanVien, TruongPhong truongPhong) { + nhanVien.setTruongPhongQuanLy(truongPhong); + } + + /** + * Tóm tắt: Xóa nhân sự; nếu là trưởng phòng thì tự ngắt liên kết nhân viên cấp dưới. + */ + public static void xoaNhanSu(List dsNhanSu, NhanSu nhanSuCanXoa) { + if (nhanSuCanXoa instanceof TruongPhong) { + var truongPhongCanXoa = (TruongPhong) nhanSuCanXoa; + for (var nhanSu : dsNhanSu) { + if (nhanSu instanceof NhanVien) { + var nhanVien = (NhanVien) nhanSu; + if (nhanVien.getTruongPhongQuanLy() == truongPhongCanXoa) { + nhanVien.setTruongPhongQuanLy(null); } } - truongPhong.setSoThanhVien(count); - truongPhong.tinhLuong(); } } + dsNhanSu.remove(nhanSuCanXoa); + capNhatLuongVaQuanLy(dsNhanSu); } - // Find index by code user public static int findIndexByCode(List dsNhanSu, String maNhanVien) { - var index = -1; for (var i = 0; i < dsNhanSu.size(); i++) { - if (dsNhanSu.get(i).getMaNhanVien().equals(maNhanVien)) { - index = i; - break; + if (dsNhanSu.get(i).getMaNhanVien().equalsIgnoreCase(maNhanVien)) { + return i; } } - return index; + return -1; } - // NhanVien transform to TruongPhong - public static TruongPhong nhanVienTransToTruongPhong(NhanSu nhanSu) { - var truongPhong = new TruongPhong(); - truongPhong.setMaNhanVien(nhanSu.getMaNhanVien()); - truongPhong.setHoTen(nhanSu.getHoTen()); - truongPhong.setSoDienThoai(nhanSu.getSoDienThoai()); - truongPhong.setSoNgayLamViec(nhanSu.getSoNgayLamViec()); - truongPhong.setSoThanhVien(0); - truongPhong.tinhLuong(); - return truongPhong; + public static NhanSu findByCode(List dsNhanSu, String maNhanVien) { + var index = findIndexByCode(dsNhanSu, maNhanVien); + return index >= 0 ? dsNhanSu.get(index) : null; + } + + public static List layDanhSachNhanVien(List dsNhanSu) { + var dsNhanVien = new ArrayList(); + for (var nhanSu : dsNhanSu) { + if (nhanSu instanceof NhanVien) { + dsNhanVien.add((NhanVien) nhanSu); + } + } + return dsNhanVien; + } + + public static List layDanhSachTruongPhong(List dsNhanSu) { + var dsTruongPhong = new ArrayList(); + for (var nhanSu : dsNhanSu) { + if (nhanSu instanceof TruongPhong) { + dsTruongPhong.add((TruongPhong) nhanSu); + } + } + return dsTruongPhong; + } + + public static List layDanhSachGiamDoc(List dsNhanSu) { + var dsGiamDoc = new ArrayList(); + for (var nhanSu : dsNhanSu) { + if (nhanSu instanceof GiamDoc) { + dsGiamDoc.add((GiamDoc) nhanSu); + } + } + return dsGiamDoc; } - // Sum Salary public static double sumSalary(List dsNhanSu) { + capNhatLuongVaQuanLy(dsNhanSu); var sum = 0d; for (var nhanSu : dsNhanSu) { sum += nhanSu.getLuongThang(); @@ -124,106 +186,102 @@ public static double sumSalary(List dsNhanSu) { return sum; } - // List max salary - public static List topSalary(List dsNhanSu) { - // find max - var dsTopSalary = new ArrayList(); - var maxSalary = dsNhanSu.get(0).getLuongThang(); - for (var nhanSu : dsNhanSu) { - if (nhanSu.getLuongThang() > maxSalary) { - maxSalary = nhanSu.getLuongThang(); + /** + * Tóm tắt: Chỉ tìm nhân viên thường có lương cao nhất, đúng yêu cầu README. + */ + public static List topSalaryNhanVien(List dsNhanSu) { + capNhatLuongVaQuanLy(dsNhanSu); + var dsNhanVien = layDanhSachNhanVien(dsNhanSu); + var dsTopSalary = new ArrayList(); + if (dsNhanVien.isEmpty()) { + return dsTopSalary; + } + + var maxSalary = dsNhanVien.get(0).getLuongThang(); + for (var nhanVien : dsNhanVien) { + if (nhanVien.getLuongThang() > maxSalary) { + maxSalary = nhanVien.getLuongThang(); } } - // add to list - for (var nhanSu : dsNhanSu) { - if (nhanSu.getLuongThang() == maxSalary) { - dsTopSalary.add(nhanSu); + + for (var nhanVien : dsNhanVien) { + if (nhanVien.getLuongThang() == maxSalary) { + dsTopSalary.add(nhanVien); } } return dsTopSalary; } - // List TruongPhong max memberF public static List topTeam(List dsNhanSu) { - // find max + capNhatLuongVaQuanLy(dsNhanSu); + var dsTruongPhong = layDanhSachTruongPhong(dsNhanSu); var dsTopTeam = new ArrayList(); - var maxTeam = 0; - for (var nhanSu : dsNhanSu) { - if (nhanSu instanceof TruongPhong) { - var truongPhong = (TruongPhong) nhanSu; - if (truongPhong.getSoThanhVien() > maxTeam) { - maxTeam = truongPhong.getSoThanhVien(); - } + if (dsTruongPhong.isEmpty()) { + return dsTopTeam; + } + + var maxTeam = dsTruongPhong.get(0).getSoThanhVien(); + for (var truongPhong : dsTruongPhong) { + if (truongPhong.getSoThanhVien() > maxTeam) { + maxTeam = truongPhong.getSoThanhVien(); } } - // add to list - for (var nhanSu : dsNhanSu) { - if (nhanSu instanceof TruongPhong) { - var truongPhong = (TruongPhong) nhanSu; - if (truongPhong.getSoThanhVien() == maxTeam) { - dsTopTeam.add(truongPhong); - } + + for (var truongPhong : dsTruongPhong) { + if (truongPhong.getSoThanhVien() == maxTeam) { + dsTopTeam.add(truongPhong); } } return dsTopTeam; } - // Sort by name public static void sortByName(List dsNhanSu) { - sort(dsNhanSu, new Comparator() { + dsNhanSu.sort(new Comparator() { @Override - public int compare(NhanSu o1, NhanSu o2) { - return o1.getHoTen().compareTo(o2.getHoTen()); + public int compare(NhanSu nhanSu1, NhanSu nhanSu2) { + return VIETNAMESE_COLLATOR.compare(nhanSu1.getHoTen(), nhanSu2.getHoTen()); } }); } - // Sort by code - public static void sortByCode(List dsNhanSu) { - sort(dsNhanSu, new Comparator() { + public static void sortBySalaryDesc(List dsNhanSu) { + capNhatLuongVaQuanLy(dsNhanSu); + dsNhanSu.sort(new Comparator() { @Override - public int compare(NhanSu o1, NhanSu o2) { - return o1.getMaNhanVien().compareTo(o2.getMaNhanVien()); + public int compare(NhanSu nhanSu1, NhanSu nhanSu2) { + return Double.compare(nhanSu2.getLuongThang(), nhanSu1.getLuongThang()); } }); } - // List GiamDoc max CoPhan public static List topShare(List dsNhanSu) { - // find max + var dsGiamDoc = layDanhSachGiamDoc(dsNhanSu); var dsTopShare = new ArrayList(); - var maxShare = 0d; - for (var nhanSu : dsNhanSu) { - if (nhanSu instanceof GiamDoc) { - var giamDoc = (GiamDoc) nhanSu; - if (giamDoc.getCoPhan() > maxShare) { - maxShare = giamDoc.getCoPhan(); - } + if (dsGiamDoc.isEmpty()) { + return dsTopShare; + } + + var maxShare = dsGiamDoc.get(0).getCoPhan(); + for (var giamDoc : dsGiamDoc) { + if (giamDoc.getCoPhan() > maxShare) { + maxShare = giamDoc.getCoPhan(); } } - // add to list - for (var nhanSu : dsNhanSu) { - if (nhanSu instanceof GiamDoc) { - var giamDoc = (GiamDoc) nhanSu; - if (giamDoc.getCoPhan() == maxShare) { - dsTopShare.add(giamDoc); - } + + for (var giamDoc : dsGiamDoc) { + if (giamDoc.getCoPhan() == maxShare) { + dsTopShare.add(giamDoc); } } return dsTopShare; } - // GiamDoc all in public static List allInGiamDoc(List dsNhanSu, double doanhThuThang) { - var dsAllIn = new ArrayList(); + capNhatLuongVaQuanLy(dsNhanSu); + var dsAllIn = layDanhSachGiamDoc(dsNhanSu); var loiNhuan = doanhThuThang - sumSalary(dsNhanSu); - for (var nhanSu : dsNhanSu) { - if (nhanSu instanceof GiamDoc) { - var giamDoc = (GiamDoc) nhanSu; - giamDoc.setThuNhap( - giamDoc.getLuongThang() + giamDoc.getCoPhan() * loiNhuan / 100); - dsAllIn.add(giamDoc); - } + for (var giamDoc : dsAllIn) { + giamDoc.setThuNhap(giamDoc.getLuongThang() + giamDoc.getCoPhan() * loiNhuan / 100); } return dsAllIn; } diff --git a/quan_ly_nhan_su/TruongPhong.java b/quan_ly_nhan_su/TruongPhong.java index 731ada5..2986b30 100644 --- a/quan_ly_nhan_su/TruongPhong.java +++ b/quan_ly_nhan_su/TruongPhong.java @@ -1,54 +1,49 @@ package quan_ly_nhan_su; -import static java.lang.String.*; -import static yan_service.YANService.*; +import static java.lang.String.format; +import static yan_service.YANService.printlnAdv; +/** + * Tóm tắt: Trưởng phòng có lương ngày 200 và nhận thêm 100 cho mỗi nhân viên + * thường đang trực tiếp thuộc quyền quản lý. + */ public class TruongPhong extends NhanSu { - // #region Fields + private static final double LUONG_NGAY = 200; + private int soThanhVien; - private final String CHUC_VU = "trưởng phòng"; - private final double LUONG_NGAY = 200; - // #endregion - // #region Methods @Override - public void tinhLuong() { - luongThang = soNgayLamViec * LUONG_NGAY + 100 * soThanhVien; + protected double getLuongNgay() { + return LUONG_NGAY; } - public void xuatSoThanhVien() { - printlnAdv(format("Số thành viên: %d", soThanhVien)); + @Override + public String getChucVu() { + return "trưởng phòng"; } @Override - public void xuatChucVu() { - printlnAdv(format("Chức vụ: %s", CHUC_VU)); + public void tinhLuong() { + luongThang = soNgayLamViec * getLuongNgay() + 100 * soThanhVien; } - @Override - public void xuatLuongThang() { - printlnAdv(format("Lương tháng: %,.0f", luongThang)); + public void xuatSoThanhVien() { + printlnAdv(format("Số nhân viên dưới quyền: %d", soThanhVien)); } @Override public void xuatNhanSu() { - super.xuatMaNhanVien(); - super.xuatHoTen(); - super.xuatSoDienThoai(); - xuatChucVu(); + xuatThongTinChung(); xuatSoThanhVien(); - super.xuatSoNgayLamViec(); xuatLuongThang(); } - // #endregion - // #region Properties public int getSoThanhVien() { return soThanhVien; } public void setSoThanhVien(int soThanhVien) { - this.soThanhVien = soThanhVien; + this.soThanhVien = Math.max(0, soThanhVien); + tinhLuong(); } - // #endregion } diff --git a/yan_service/YANConstant.java b/yan_service/YANConstant.java index c716960..968727e 100644 --- a/yan_service/YANConstant.java +++ b/yan_service/YANConstant.java @@ -1,79 +1,83 @@ package yan_service; +/** + * Tóm tắt: Khai báo chiều rộng căn giữa và các mã màu ANSI dùng chung cho + * giao diện console của toàn bộ bài tập. + */ public class YANConstant { - // Constant + // Chiều rộng chuẩn để căn giữa nội dung khi in ra console. public static final int WIDTH = 70; - // Reset - public static final String RESET = "\033[0m"; // Text Reset + // Đưa màu chữ về mặc định. + public static final String RESET = "\033[0m"; - // Regular Colors - public static final String BLACK = "\033[0;30m"; // BLACK - public static final String RED = "\033[0;31m"; // RED - public static final String GREEN = "\033[0;32m"; // GREEN - public static final String YELLOW = "\033[0;33m"; // YELLOW - public static final String BLUE = "\033[0;34m"; // BLUE - public static final String PURPLE = "\033[0;35m"; // PURPLE - public static final String CYAN = "\033[0;36m"; // CYAN - public static final String WHITE = "\033[0;37m"; // WHITE + // Màu chữ thường. + public static final String BLACK = "\033[0;30m"; + public static final String RED = "\033[0;31m"; + public static final String GREEN = "\033[0;32m"; + public static final String YELLOW = "\033[0;33m"; + public static final String BLUE = "\033[0;34m"; + public static final String PURPLE = "\033[0;35m"; + public static final String CYAN = "\033[0;36m"; + public static final String WHITE = "\033[0;37m"; - // Bold - public static final String BLACK_BOLD = "\033[1;30m"; // BLACK - public static final String RED_BOLD = "\033[1;31m"; // RED - public static final String GREEN_BOLD = "\033[1;32m"; // GREEN - public static final String YELLOW_BOLD = "\033[1;33m"; // YELLOW - public static final String BLUE_BOLD = "\033[1;34m"; // BLUE - public static final String PURPLE_BOLD = "\033[1;35m"; // PURPLE - public static final String CYAN_BOLD = "\033[1;36m"; // CYAN - public static final String WHITE_BOLD = "\033[1;37m"; // WHITE + // Màu chữ đậm. + public static final String BLACK_BOLD = "\033[1;30m"; + public static final String RED_BOLD = "\033[1;31m"; + public static final String GREEN_BOLD = "\033[1;32m"; + public static final String YELLOW_BOLD = "\033[1;33m"; + public static final String BLUE_BOLD = "\033[1;34m"; + public static final String PURPLE_BOLD = "\033[1;35m"; + public static final String CYAN_BOLD = "\033[1;36m"; + public static final String WHITE_BOLD = "\033[1;37m"; - // Underline - public static final String BLACK_UNDERLINED = "\033[4;30m"; // BLACK - public static final String RED_UNDERLINED = "\033[4;31m"; // RED - public static final String GREEN_UNDERLINED = "\033[4;32m"; // GREEN - public static final String YELLOW_UNDERLINED = "\033[4;33m"; // YELLOW - public static final String BLUE_UNDERLINED = "\033[4;34m"; // BLUE - public static final String PURPLE_UNDERLINED = "\033[4;35m"; // PURPLE - public static final String CYAN_UNDERLINED = "\033[4;36m"; // CYAN - public static final String WHITE_UNDERLINED = "\033[4;37m"; // WHITE + // Màu chữ có gạch chân. + public static final String BLACK_UNDERLINED = "\033[4;30m"; + public static final String RED_UNDERLINED = "\033[4;31m"; + public static final String GREEN_UNDERLINED = "\033[4;32m"; + public static final String YELLOW_UNDERLINED = "\033[4;33m"; + public static final String BLUE_UNDERLINED = "\033[4;34m"; + public static final String PURPLE_UNDERLINED = "\033[4;35m"; + public static final String CYAN_UNDERLINED = "\033[4;36m"; + public static final String WHITE_UNDERLINED = "\033[4;37m"; - // Background - public static final String BLACK_BACKGROUND = "\033[40m"; // BLACK - public static final String RED_BACKGROUND = "\033[41m"; // RED - public static final String GREEN_BACKGROUND = "\033[42m"; // GREEN - public static final String YELLOW_BACKGROUND = "\033[43m"; // YELLOW - public static final String BLUE_BACKGROUND = "\033[44m"; // BLUE - public static final String PURPLE_BACKGROUND = "\033[45m"; // PURPLE - public static final String CYAN_BACKGROUND = "\033[46m"; // CYAN - public static final String WHITE_BACKGROUND = "\033[47m"; // WHITE + // Màu nền. + public static final String BLACK_BACKGROUND = "\033[40m"; + public static final String RED_BACKGROUND = "\033[41m"; + public static final String GREEN_BACKGROUND = "\033[42m"; + public static final String YELLOW_BACKGROUND = "\033[43m"; + public static final String BLUE_BACKGROUND = "\033[44m"; + public static final String PURPLE_BACKGROUND = "\033[45m"; + public static final String CYAN_BACKGROUND = "\033[46m"; + public static final String WHITE_BACKGROUND = "\033[47m"; - // High Intensity - public static final String BLACK_BRIGHT = "\033[0;90m"; // BLACK - public static final String RED_BRIGHT = "\033[0;91m"; // RED - public static final String GREEN_BRIGHT = "\033[0;92m"; // GREEN - public static final String YELLOW_BRIGHT = "\033[0;93m"; // YELLOW - public static final String BLUE_BRIGHT = "\033[0;94m"; // BLUE - public static final String PURPLE_BRIGHT = "\033[0;95m"; // PURPLE - public static final String CYAN_BRIGHT = "\033[0;96m"; // CYAN - public static final String WHITE_BRIGHT = "\033[0;97m"; // WHITE + // Màu chữ sáng. + public static final String BLACK_BRIGHT = "\033[0;90m"; + public static final String RED_BRIGHT = "\033[0;91m"; + public static final String GREEN_BRIGHT = "\033[0;92m"; + public static final String YELLOW_BRIGHT = "\033[0;93m"; + public static final String BLUE_BRIGHT = "\033[0;94m"; + public static final String PURPLE_BRIGHT = "\033[0;95m"; + public static final String CYAN_BRIGHT = "\033[0;96m"; + public static final String WHITE_BRIGHT = "\033[0;97m"; - // Bold High Intensity - public static final String BLACK_BOLD_BRIGHT = "\033[1;90m"; // BLACK - public static final String RED_BOLD_BRIGHT = "\033[1;91m"; // RED - public static final String GREEN_BOLD_BRIGHT = "\033[1;92m"; // GREEN - public static final String YELLOW_BOLD_BRIGHT = "\033[1;93m"; // YELLOW - public static final String BLUE_BOLD_BRIGHT = "\033[1;94m"; // BLUE - public static final String PURPLE_BOLD_BRIGHT = "\033[1;95m"; // PURPLE - public static final String CYAN_BOLD_BRIGHT = "\033[1;96m"; // CYAN - public static final String WHITE_BOLD_BRIGHT = "\033[1;97m"; // WHITE + // Màu chữ sáng và đậm. + public static final String BLACK_BOLD_BRIGHT = "\033[1;90m"; + public static final String RED_BOLD_BRIGHT = "\033[1;91m"; + public static final String GREEN_BOLD_BRIGHT = "\033[1;92m"; + public static final String YELLOW_BOLD_BRIGHT = "\033[1;93m"; + public static final String BLUE_BOLD_BRIGHT = "\033[1;94m"; + public static final String PURPLE_BOLD_BRIGHT = "\033[1;95m"; + public static final String CYAN_BOLD_BRIGHT = "\033[1;96m"; + public static final String WHITE_BOLD_BRIGHT = "\033[1;97m"; - // High Intensity backgrounds - public static final String BLACK_BACKGROUND_BRIGHT = "\033[0;100m"; // BLACK - public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m"; // RED - public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m"; // GREEN - public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m"; // YELLOW - public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m"; // BLUE - public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; // PURPLE - public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; // CYAN - public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; // WHITE + // Màu nền sáng. + public static final String BLACK_BACKGROUND_BRIGHT = "\033[0;100m"; + public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m"; + public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m"; + public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m"; + public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m"; + public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; + public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; + public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; } diff --git a/yan_service/YANService.java b/yan_service/YANService.java index 8137e24..7ee9ae2 100644 --- a/yan_service/YANService.java +++ b/yan_service/YANService.java @@ -10,16 +10,20 @@ import static java.lang.System.*; import static yan_service.YANConstant.*; +/** + * Tóm tắt: Lớp tiện ích dùng chung cho các bài console, bao gồm nhập số/ngày, + * căn giữa nội dung, chuyển đổi chữ hoa-thường và hỏi người dùng có tiếp tục. + */ public class YANService { - // Fields + // Scanner dùng chung cho các hàm nhập dữ liệu số và ngày. private static final Scanner mScan = new Scanner(in); - // Parse int advanced + // Chuyển một ký tự số thành số nguyên. public static int parseIntAdv(Character c) { return parseInt(valueOf(c)); } - // Try parse int + // Kiểm tra một ký tự có thể chuyển thành số nguyên hay không. public static boolean tryParseInt(Character c) { var isSuccess = true; try { @@ -30,7 +34,7 @@ public static boolean tryParseInt(Character c) { return isSuccess; } - // Try parse int + // Kiểm tra một chuỗi có thể chuyển thành số nguyên hay không. public static boolean tryParseInt(String s) { var isSuccess = true; try { @@ -41,7 +45,7 @@ public static boolean tryParseInt(String s) { return isSuccess; } - // Scan int + // Nhập số nguyên, nếu sai kiểu sẽ yêu cầu nhập lại. public static int scanInt() { var n = 0; var s = mScan.nextLine(); @@ -54,7 +58,7 @@ public static int scanInt() { return n; } - // Number limit int + // Nhập số nguyên trong đoạn [min, max]. public static int numLimit(int min, int max) { var n = scanInt(); if (n < min || n > max) { @@ -64,57 +68,57 @@ public static int numLimit(int min, int max) { return n; } - // Number limit int + // Nhập số nguyên trong khoảng (min, max). public static int numLimitEx(int min, int max) { var n = scanInt(); if (n <= min || n >= max) { printAdv(RED, "Không xác định, xin nhập lại: ", RESET); - n = numLimit(min, max); + n = numLimitEx(min, max); } return n; } - // Parse double advanced + // Chuyển một ký tự số thành số thực. public static double parseDubAdv(Character c) { return parseDouble(valueOf(c)); } - // Try parse double + // Kiểm tra một ký tự có thể chuyển thành số thực hữu hạn hay không. public static boolean tryParseDub(Character c) { var isSuccess = true; try { - parseDouble(valueOf(c)); + isSuccess = isFinite(parseDouble(valueOf(c))); } catch (Exception e) { isSuccess = false; } return isSuccess; } - // Try parse double + // Kiểm tra một chuỗi có thể chuyển thành số thực hữu hạn hay không. public static boolean tryParseDub(String s) { var isSuccess = true; try { - parseDouble(s); + isSuccess = isFinite(parseDouble(s)); } catch (Exception e) { isSuccess = false; } return isSuccess; } - // Scan double + // Nhập số thực, nếu sai kiểu sẽ yêu cầu nhập lại. public static double scanDub() { var n = 0d; var s = mScan.nextLine(); if (tryParseDub(s)) { n = parseDouble(s); } else { - printAdv(RED, "Dữ liện bạn nhập không phải số, xin nhập lại: ", RESET); + printAdv(RED, "Dữ liệu bạn nhập không phải số, xin nhập lại: ", RESET); n = scanDub(); } return n; } - // Number limit double + // Nhập số thực trong đoạn [min, max]. public static double numLimit(double min, double max) { var n = scanDub(); if (n < min || n > max) { @@ -124,22 +128,22 @@ public static double numLimit(double min, double max) { return n; } - // Number limit double + // Nhập số thực trong khoảng (min, max). public static double numLimitEx(double min, double max) { var n = scanDub(); if (n <= min || n >= max) { printAdv(RED, "Không xác định, xin nhập lại: ", RESET); - n = numLimit(min, max); + n = numLimitEx(min, max); } return n; } - // Double to perfect number + // In số thực gọn hơn khi phần thập phân bằng 0. public static String writePerfectDub(double n) { return n == (int) n ? String.valueOf((int) n) : String.valueOf(n); } - // Try parse date exact + // Kiểm tra chuỗi ngày có đúng định dạng yêu cầu hay không. public static boolean tryParseDateExact(String strDate, String strFormat) { var isSuccess = true; try { @@ -152,7 +156,7 @@ public static boolean tryParseDateExact(String strDate, String strFormat) { return isSuccess; } - // Parse date exact + // Chuyển chuỗi ngày sang Date theo định dạng chặt chẽ. public static Date parseDateExact(String strDate, String strFormat) { var dateFormat = new SimpleDateFormat(strFormat); dateFormat.setLenient(false); @@ -163,7 +167,7 @@ public static Date parseDateExact(String strDate, String strFormat) { } } - // Scan date + // Nhập ngày theo định dạng truyền vào, sai định dạng sẽ yêu cầu nhập lại. public static Date scanDate(String strFormat) { var date = new Date(); var s = mScan.nextLine(); @@ -176,12 +180,12 @@ public static Date scanDate(String strFormat) { return date; } - // Date to string dd/mm/yyyy + // Định dạng Date về chuỗi dd/MM/yyyy. public static String dateToString(Date date) { return new SimpleDateFormat("dd/MM/yyyy").format(date); } - // Print advanced + // In một chuỗi được căn giữa theo WIDTH. public static void printAdv(String s) { for (var i = 1; i <= (WIDTH - s.length()) / 2; i++) { out.print(" "); @@ -189,7 +193,7 @@ public static void printAdv(String s) { out.print(s); } - // Print advanced color + // In một chuỗi căn giữa kèm màu mở đầu. public static void printAdv(String color, String s) { for (var i = 1; i <= (WIDTH - s.length()) / 2; i++) { out.print(" "); @@ -197,7 +201,7 @@ public static void printAdv(String color, String s) { out.print(color + s); } - // Print advanced multi color + // In một chuỗi căn giữa với màu mở đầu và mã reset/kết thúc. public static void printAdv(String colorStart, String s, String colorEnd) { for (var i = 1; i <= (WIDTH - s.length()) / 2; i++) { out.print(" "); @@ -205,7 +209,7 @@ public static void printAdv(String colorStart, String s, String colorEnd) { out.print(colorStart + s + colorEnd); } - // Print line advanced + // In một dòng căn giữa theo WIDTH. public static void printlnAdv(String s) { for (var i = 1; i <= (WIDTH - s.length()) / 2; i++) { out.print(" "); @@ -213,7 +217,7 @@ public static void printlnAdv(String s) { out.println(s); } - // Print line advanced color + // In một dòng căn giữa kèm màu mở đầu. public static void printlnAdv(String color, String s) { for (var i = 1; i <= (WIDTH - s.length()) / 2; i++) { out.print(" "); @@ -221,7 +225,7 @@ public static void printlnAdv(String color, String s) { out.println(color + s); } - // Print line advanced multi color + // In một dòng căn giữa với màu mở đầu và mã reset/kết thúc. public static void printlnAdv(String colorStart, String s, String colorEnd) { for (var i = 1; i <= (WIDTH - s.length()) / 2; i++) { out.print(" "); @@ -229,7 +233,7 @@ public static void printlnAdv(String colorStart, String s, String colorEnd) { out.println(colorStart + s + colorEnd); } - // Check whitespace + // Kiểm tra chuỗi chỉ gồm ký tự trắng. public static boolean isSpace(String s) { var isSuccess = true; for (var i = 0; i < s.length(); i++) { @@ -241,55 +245,51 @@ public static boolean isSpace(String s) { return isSuccess; } - // Check null or empty + // Kiểm tra chuỗi null hoặc rỗng. public static boolean isNullOrEmpty(String s) { return s == null || s.length() == 0; } - // Check null or whitespace + // Kiểm tra chuỗi null, rỗng hoặc chỉ gồm khoảng trắng. public static boolean isNullOrWhitespace(String s) { return isNullOrEmpty(s) || isSpace(s); } - // Covert to title case + // Chuyển chuỗi về kiểu viết hoa chữ cái đầu từng từ. public static String toTitleCase(String s) { - var list = new ArrayList(); - var str = ""; + var strBuilder = new StringBuilder(); if (!isNullOrWhitespace(s)) { var cst = s.charAt(0); cst = isWhitespace(cst) ? cst : toUpperCase(cst); - list.add(cst); + strBuilder.append(cst); for (var i = 0; i < s.length() - 1; i++) { var c = s.charAt(i + 1); if (isWhitespace(s.charAt(i)) && !isWhitespace(c)) { - list.add(toUpperCase(c)); + strBuilder.append(toUpperCase(c)); } else { - list.add(c); + strBuilder.append(c); } } - for (var item : list) { - str += item; - } } - return str; + return strBuilder.toString(); } - // Convert to lower case advanced + // Chuyển chữ thường nhưng giữ nguyên null/chuỗi trắng. public static String toLowerCaseAdv(String s) { return isNullOrWhitespace(s) ? s : s.toLowerCase(); } - // Convert to upper case advanced + // Chuyển chữ hoa nhưng giữ nguyên null/chuỗi trắng. public static String toUpperCaseAdv(String s) { return isNullOrWhitespace(s) ? s : s.toUpperCase(); } - // Convert to title case advanced + // Chuyển title case nhưng giữ nguyên null/chuỗi trắng. public static String toTitleCaseAdv(String s) { return isNullOrWhitespace(s) ? s : toTitleCase(s.toLowerCase()); } - // Credit + // Hỏi người dùng có muốn tiếp tục chương trình hiện tại hay không. public static int credit() { printlnAdv(PURPLE, "Bạn có muốn tiếp tục?"); printlnAdv("1. Có ");