SƠ ĐỒ TỔNG QUÁT CHO BÀI TẬP
┌─────────────────────────────────────────────────────────────┐
│ INTERFACES (Hợp đồng) │
├─────────────────────────────────────────────────────────────┤
│ IPrintable IStorable ICalculable │
│ ├── Print() ├── Serialize() ├── Calculate() │
│ └── GetSummary() └── Deserialize() │
└─────────────────────────────────────────────────────────────┘
│
│ Implement (Triển khai)
▼
┌─────────────────────────────────────────────────────────────┐
│ NHÂN VIÊN (Abstract Class) │
├─────────────────────────────────────────────────────────────┤
│ Kế thừa: │
│ ├── IPrintable → Print(), GetSummary() │
│ ├── IStorable → Serialize(), Deserialize() │
│ └── ICalculable → Calculate() (Tính lương) │
└─────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
│ NhanVienVanPhong │ │ NhanVienSanXuat │ │ NhanVienQuanLy │
│ (Lớp con 1) │ │ (Lớp con 2) │ │ (Lớp con 3) │
└───────────────────┘ └───────────────────┘ └───────────────────┘BƯỚC 1: TẠO PROJECT MỚI
1.1. Mở Visual Studio
text
File → New → Project
Hoặc nhấn: Ctrl + Shift + N
1.2. Chọn loại Project
Chọn Console App (.NET Core)
Nhấn Next
1.3. Đặt tên Project
Project name: Bai2_Interface
Location: D:\CSharp\LapTrinhHuongDoiTuong Solution: LapTrinhHuongDoiTuong (Add to Solution)
Nhấn Next
1.4. Chọn Framework
Chọn .NET 6.0 hoặc .NET 8.0
Nhấn Create
BƯỚC 2: TẠO CẤU TRÚC THƯ MỤC
2.1. Tạo thư mục
Bai2_Interface (Project)
├── Interfaces/ ← Chứa các Interface │ ├── IPrintable.cs │ ├── IStorable.cs │ └── ICalculable.cs ├── Models/ ← Chứa các lớp │ ├── NhanVien.cs │ ├── NhanVienVanPhong.cs │ ├── NhanVienSanXuat.cs │ └── NhanVienQuanLy.cs └── Program.cs ← Chạy test
2.2. Tạo thư mục
Click chuột phải vào Project → Add → New Folder → Đặt tên
InterfacesClick chuột phải vào Project → Add → New Folder → Đặt tên
Models
BƯỚC 3: XÂY DỰNG CÁC INTERFACE
3.1. Interface IPrintable.cs
Click chuột phải vào thư mục Interfaces
Chọn Add → Class → Đặt tên
IPrintable.csNhấn Add
Viết code:
using System; namespace Bai2_Interface.Interfaces { /// <summary> /// Interface IPrintable - Định nghĩa hành vi in ấn /// Interface này quy định: Lớp nào implement phải có khả năng in ấn /// </summary> public interface IPrintable { /// <summary> /// Phương thức Print() - In thông tin ra màn hình /// Không có body (không triển khai) /// Lớp implement phải tự triển khai /// </summary> void Print(); /// <summary> /// Phương thức GetSummary() - Trả về chuỗi tóm tắt /// Không có body /// </summary> string GetSummary(); } }
.2. Interface IStorable.cs
Click chuột phải vào thư mục Interfaces
Chọn Add → Class → Đặt tên
IStorable.csNhấn Add
Viết code:
csharp
using System; namespace Bai2_Interface.Interfaces { /// <summary> /// Interface IStorable - Định nghĩa hành vi lưu trữ /// Interface này quy định: Lớp nào implement phải có khả năng serialize/deserialize /// </summary> public interface IStorable { /// <summary> /// Serialize() - Chuyển đối tượng thành chuỗi để lưu trữ /// </summary> string Serialize(); /// <summary> /// Deserialize() - Chuyển chuỗi thành đối tượng /// </summary> /// <param name="data">Chuỗi dữ liệu cần chuyển đổi</param> void Deserialize(string data); } }
3.3. Interface ICalculable.cs
Click chuột phải vào thư mục Interfaces
Chọn Add → Class → Đặt tên
ICalculable.csNhấn Add
Viết code:
csharp
using System; namespace Bai2_Interface.Interfaces { /// <summary> /// Interface ICalculable - Định nghĩa hành vi tính toán /// Interface này quy định: Lớp nào implement phải có khả năng tính toán /// </summary> public interface ICalculable { /// <summary> /// Calculate() - Thực hiện tính toán (ví dụ: tính lương) /// </summary> double Calculate(); } }
BƯỚC 4: XÂY DỰNG CÁC LỚP IMPLEMENT INTERFACE
4.1. Lớp NhanVien.cs (Abstract Class)
Click chuột phải vào thư mục Models
Chọn Add → Class → Đặt tên
NhanVien.csNhấn Add
Viết code:
using System;
using Bai2_Interface.Interfaces; namespace Bai2_Interface.Models { /// <summary> /// Lớp trừu tượng NhanVien /// Implement 3 Interface: IPrintable, IStorable, ICalculable /// </summary> public abstract class NhanVien : IPrintable, IStorable, ICalculable { // === FIELDS === private string _maNV; private string _hoTen; private DateTime _ngaySinh; private double _luongCoBan; // === PROPERTIES === public string MaNV { get { return _maNV; } set { if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Mã NV không được để trống!"); _maNV = value.Trim(); } } public string HoTen { get { return _hoTen; } set { if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Họ tên không được để trống!"); _hoTen = value.Trim(); } } public DateTime NgaySinh { get { return _ngaySinh; } set { if (value > DateTime.Now) throw new ArgumentException("Ngày sinh không được trong tương lai!"); if (value < new DateTime(1900, 1, 1)) throw new ArgumentException("Ngày sinh không hợp lệ!"); _ngaySinh = value; } } public double LuongCoBan { get { return _luongCoBan; } set { if (value < 0) throw new ArgumentException("Lương cơ bản không được âm!"); _luongCoBan = value; } } // === CONSTRUCTORS === public NhanVien() { _maNV = "NV001"; _hoTen = "Chưa xác định"; _ngaySinh = new DateTime(2000, 1, 1); _luongCoBan = 0; } public NhanVien(string ma, string ten, DateTime ngaySinh, double luong) { MaNV = ma; HoTen = ten; NgaySinh = ngaySinh; LuongCoBan = luong; } // === ABSTRACT METHOD === public abstract double Calculate(); // Implement ICalculable // === VIRTUAL METHOD === public virtual void HienThi() { Console.WriteLine("═══════════════════════════════════════"); Console.WriteLine($" Mã NV : {_maNV}"); Console.WriteLine($" Họ tên : {_hoTen}"); Console.WriteLine($" Ngày sinh : {_ngaySinh:dd/MM/yyyy}"); Console.WriteLine($" Lương CB : {_luongCoBan:N0} VND"); Console.WriteLine($" Lương TT : {Calculate():N0} VND"); Console.WriteLine("═══════════════════════════════════════"); } // === IMPLEMENT IPrintable === /// <summary> /// Implement phương thức Print() từ IPrintable /// In thông tin nhân viên /// </summary> public virtual void Print() { Console.WriteLine($"--- NHÂN VIÊN: {_hoTen} ---"); HienThi(); } /// <summary> /// Implement phương thức GetSummary() từ IPrintable /// Trả về chuỗi tóm tắt /// </summary> public virtual string GetSummary() { return $"{_maNV}|{_hoTen}|{Calculate():N0}"; } // === IMPLEMENT IStorable === /// <summary> /// Implement phương thức Serialize() từ IStorable /// Chuyển đối tượng thành chuỗi để lưu /// </summary> public virtual string Serialize() { // Định dạng: TênLớp|Mã|Tên|NgàySinh|LươngCB return $"{GetType().Name}|{_maNV}|{_hoTen}|{_ngaySinh:yyyy-MM-dd}|{_luongCoBan}"; } /// <summary> /// Implement phương thức Deserialize() từ IStorable /// Chuyển chuỗi thành đối tượng /// </summary> public virtual void Deserialize(string data) { // Tách chuỗi thành các phần string[] parts = data.Split('|'); if (parts.Length >= 5) { MaNV = parts[1]; // Mã NV HoTen = parts[2]; // Họ tên NgaySinh = DateTime.Parse(parts[3]); // Ngày sinh LuongCoBan = double.Parse(parts[4]); // Lương CB } } } }
4.2. Lớp NhanVienVanPhong.cs
using System;
using Bai2_Interface.Interfaces; namespace Bai2_Interface.Models { /// <summary> /// Lớp NhanVienVanPhong kế thừa từ NhanVien /// Tự động implement các Interface từ lớp cha /// </summary> public class NhanVienVanPhong : NhanVien { // === FIELD RIÊNG === private int _soNgayLamViec; // === PROPERTY RIÊNG === public int SoNgayLamViec { get { return _soNgayLamViec; } set { if (value < 0 || value > 31) throw new ArgumentException("Số ngày làm phải từ 0 đến 31!"); _soNgayLamViec = value; } } // === CONSTRUCTORS === public NhanVienVanPhong() : base() { _soNgayLamViec = 0; } public NhanVienVanPhong(string ma, string ten, DateTime ngaySinh, double luong, int soNgay) : base(ma, ten, ngaySinh, luong) { SoNgayLamViec = soNgay; } // === IMPLEMENT ABSTRACT Calculate() === /// <summary> /// Tính lương nhân viên văn phòng /// Lương = Lương CB + Số ngày làm × 200,000 /// </summary> public override double Calculate() { return LuongCoBan + (_soNgayLamViec * 200000); } // === GHI ĐÈ PHƯƠNG THỨC HIỂN THỊ === public override void HienThi() { base.HienThi(); Console.WriteLine($" Loại : Nhân viên văn phòng"); Console.WriteLine($" Số ngày làm: {_soNgayLamViec}"); Console.WriteLine("═══════════════════════════════════════"); } // === GHI ĐÈ CÁC PHƯƠNG THỨC TỪ INTERFACE === public override string GetSummary() { return $"{base.GetSummary()}|VP|{_soNgayLamViec}"; } public override string Serialize() { return $"{base.Serialize()}|{_soNgayLamViec}"; } public override void Deserialize(string data) { base.Deserialize(data); string[] parts = data.Split('|'); if (parts.Length >= 6) { SoNgayLamViec = int.Parse(parts[5]); } } } }
4.3. Lớp NhanVienSanXuat.cs
using System;
using Bai2_Interface.Interfaces; namespace Bai2_Interface.Models { /// <summary> /// Lớp NhanVienSanXuat kế thừa từ NhanVien /// </summary> public class NhanVienSanXuat : NhanVien { // === FIELDS RIÊNG === private int _soSanPham; private double _donGiaSanPham; // === PROPERTIES RIÊNG === public int SoSanPham { get { return _soSanPham; } set { if (value < 0) throw new ArgumentException("Số sản phẩm không được âm!"); _soSanPham = value; } } public double DonGiaSanPham { get { return _donGiaSanPham; } set { if (value < 0) throw new ArgumentException("Đơn giá không được âm!"); _donGiaSanPham = value; } } // === CONSTRUCTORS === public NhanVienSanXuat() : base() { _soSanPham = 0; _donGiaSanPham = 50000; } public NhanVienSanXuat(string ma, string ten, DateTime ngaySinh, double luong, int soSanPham, double donGia = 50000) : base(ma, ten, ngaySinh, luong) { SoSanPham = soSanPham; DonGiaSanPham = donGia; } // === IMPLEMENT ABSTRACT Calculate() === /// <summary> /// Tính lương nhân viên sản xuất /// Lương = Lương CB + Số sản phẩm × Đơn giá /// </summary> public override double Calculate() { return LuongCoBan + (_soSanPham * _donGiaSanPham); } public override void HienThi() { base.HienThi(); Console.WriteLine($" Loại : Nhân viên sản xuất"); Console.WriteLine($" Số SP : {_soSanPham}"); Console.WriteLine($" Đơn giá SP : {_donGiaSanPham:N0} VND"); Console.WriteLine("═══════════════════════════════════════"); } public override string GetSummary() { return $"{base.GetSummary()}|SX|{_soSanPham}|{_donGiaSanPham}"; } public override string Serialize() { return $"{base.Serialize()}|{_soSanPham}|{_donGiaSanPham}"; } public override void Deserialize(string data) { base.Deserialize(data); string[] parts = data.Split('|'); if (parts.Length >= 7) { SoSanPham = int.Parse(parts[5]); DonGiaSanPham = double.Parse(parts[6]); } } } }
4.4. Lớp NhanVienQuanLy.cs
using System; using Bai2_Interface.Interfaces; namespace Bai2_Interface.Models { /// <summary> /// Lớp NhanVienQuanLy kế thừa từ NhanVien /// </summary> public class NhanVienQuanLy : NhanVien { // === FIELDS RIÊNG === private double _thuong; private int _soNhanVienQuanLy; // === PROPERTIES RIÊNG === public double Thuong { get { return _thuong; } set { if (value < 0) throw new ArgumentException("Thưởng không được âm!"); _thuong = value; } } public int SoNhanVienQuanLy { get { return _soNhanVienQuanLy; } set { if (value < 0) throw new ArgumentException("Số NV quản lý không được âm!"); _soNhanVienQuanLy = value; } } // === CONSTRUCTORS === public NhanVienQuanLy() : base() { _thuong = 0; _soNhanVienQuanLy = 0; } public NhanVienQuanLy(string ma, string ten, DateTime ngaySinh, double luong, double thuong, int soNV) : base(ma, ten, ngaySinh, luong) { Thuong = thuong; SoNhanVienQuanLy = soNV; } // === IMPLEMENT ABSTRACT Calculate() === /// <summary> /// Tính lương nhân viên quản lý /// Lương = Lương CB × 2 + Thưởng /// </summary> public override double Calculate() { return LuongCoBan * 2 + _thuong; } public override void HienThi() { base.HienThi(); Console.WriteLine($" Loại : Nhân viên quản lý"); Console.WriteLine($" Thưởng : {_thuong:N0} VND"); Console.WriteLine($" Số NV QL : {_soNhanVienQuanLy}"); Console.WriteLine("═══════════════════════════════════════"); } public override string GetSummary() { return $"{base.GetSummary()}|QL|{_thuong}|{_soNhanVienQuanLy}"; } public override string Serialize() { return $"{base.Serialize()}|{_thuong}|{_soNhanVienQuanLy}"; } public override void Deserialize(string data) { base.Deserialize(data); string[] parts = data.Split('|'); if (parts.Length >= 7) { Thuong = double.Parse(parts[5]); SoNhanVienQuanLy = int.Parse(parts[6]); } } } }
BƯỚC 5: CODE TEST (Program.cs)
using System;
using System.Collections.Generic; using Bai2_Interface.Interfaces; using Bai2_Interface.Models; namespace Bai2_Interface { class Program { static void Main(string[] args) { Console.OutputEncoding = System.Text.Encoding.UTF8; Console.WriteLine("═══════════════════════════════════════════════════"); Console.WriteLine(" BÀI TẬP 2: XÂY DỰNG INTERFACE CHO HỆ THỐNG"); Console.WriteLine("═══════════════════════════════════════════════════\n"); // ================================================================ // PHẦN 1: TẠO DANH SÁCH NHÂN VIÊN // ================================================================ List<NhanVien> danhSachNV = new List<NhanVien>(); danhSachNV.Add(new NhanVienVanPhong("NV001", "Nguyễn Văn A", new DateTime(1990, 5, 10), 8000000, 22)); danhSachNV.Add(new NhanVienSanXuat("NV002", "Trần Thị B", new DateTime(1995, 8, 15), 6000000, 150)); danhSachNV.Add(new NhanVienQuanLy("NV003", "Lê Văn C", new DateTime(1985, 12, 20), 12000000, 5000000, 10)); Console.WriteLine("▶ DANH SÁCH NHÂN VIÊN (ĐA HÌNH):"); Console.WriteLine("───────────────────────────────────────────────────\n"); // ================================================================ // PHẦN 2: DEMO INTERFACE IPrintable // ================================================================ Console.WriteLine("1. DEMO INTERFACE IPRINTABLE:"); Console.WriteLine("───────────────────────────────────────────────────\n"); foreach (NhanVien nv in danhSachNV) { nv.Print(); // Gọi phương thức từ IPrintable Console.WriteLine($" Tóm tắt: {nv.GetSummary()}"); Console.WriteLine(); } // ================================================================ // PHẦN 3: DEMO INTERFACE IStorable // ================================================================ Console.WriteLine("2. DEMO INTERFACE ISTORABLE:"); Console.WriteLine("───────────────────────────────────────────────────\n"); foreach (NhanVien nv in danhSachNV) { string serialized = nv.Serialize(); Console.WriteLine($" Serialize: {serialized}"); // Tạo đối tượng mới và Deserialize NhanVien nvMoi = new NhanVienVanPhong(); // Tạm thời nvMoi.Deserialize(serialized); Console.WriteLine($" Deserialize: {nvMoi.GetSummary()}"); Console.WriteLine(); } // ================================================================ // PHẦN 4: DEMO INTERFACE ICalculable // ================================================================ Console.WriteLine("3. DEMO INTERFACE ICALCULABLE:"); Console.WriteLine("───────────────────────────────────────────────────\n"); Console.WriteLine(" BẢNG TÍNH LƯƠNG NHÂN VIÊN:"); Console.WriteLine(" ───────────────────────────────────────────────"); Console.WriteLine($" {"Mã NV",-10} {"Họ tên",-20} {"Lương TT",15}"); Console.WriteLine(" ───────────────────────────────────────────────"); foreach (NhanVien nv in danhSachNV) { // Gọi Calculate() từ ICalculable Console.WriteLine($" {nv.MaNV,-10} {nv.HoTen,-20} {nv.Calculate(),15:N0}"); } Console.WriteLine(" ───────────────────────────────────────────────"); // ================================================================ // PHẦN 5: SỬ DỤNG INTERFACE LÀM KIỂU DỮ LIỆU // ================================================================ Console.WriteLine("\n4. SỬ DỤNG INTERFACE LÀM KIỂU DỮ LIỆU:"); Console.WriteLine("───────────────────────────────────────────────────\n"); // Có thể tạo danh sách kiểu Interface List<IPrintable> printableList = new List<IPrintable>(); foreach (NhanVien nv in danhSachNV) { printableList.Add(nv); // NhanVien implement IPrintable } Console.WriteLine(" Danh sách IPrintable (đa hình):"); foreach (IPrintable item in printableList) { Console.WriteLine($" - {item.GetSummary()}"); } // ================================================================ // PHẦN 6: THỬ NHẬP DỮ LIỆU TỪ SERIALIZE // ================================================================ Console.WriteLine("\n5. THỬ NHẬP DỮ LIỆU TỪ CHUỖI SERIALIZE:"); Console.WriteLine("───────────────────────────────────────────────────\n"); try { Console.Write(" Nhập chuỗi Serialize: "); string input = Console.ReadLine(); if (!string.IsNullOrEmpty(input)) { // Tạo đối tượng từ chuỗi string[] parts = input.Split('|'); NhanVien nvFromData = null; switch (parts[0]) { case "NhanVienVanPhong": nvFromData = new NhanVienVanPhong(); break; case "NhanVienSanXuat": nvFromData = new NhanVienSanXuat(); break; case "NhanVienQuanLy": nvFromData = new NhanVienQuanLy(); break; default: Console.WriteLine(" ❌ Loại nhân viên không hợp lệ!"); break; } if (nvFromData != null) { nvFromData.Deserialize(input); Console.WriteLine(" ✅ Đã tạo đối tượng từ dữ liệu:"); nvFromData.Print(); } } } catch (Exception ex) { Console.WriteLine($" ❌ Lỗi: {ex.Message}"); } Console.WriteLine("\n═══════════════════════════════════════════════════"); Console.WriteLine("NHẤN PHÍM BẤT KỲ ĐỂ THOÁT..."); Console.ReadKey(); } } }