Bài tập 3(B9_C#) LỚP TÀI KHOẢN NGÂN HÀNG (TAIKHOANNANGHANG)

MỤC TIÊU BÀI HỌC

Sau khi hoàn thành bài tập này, bạn sẽ:

  1. ✅ Xây dựng lớp TaiKhoanNganHang mô phỏng tài khoản ngân hàng

  2. ✅ Thực hành đóng gói dữ liệu với private fields

  3. ✅ Sử dụng kiểu decimal cho số dư tài khoản

  4. ✅ Xây dựng các phương thức: nạp tiền, rút tiền, đổi mật khẩu

  5. ✅ Thực hành validation khi giao dịch

  6. ✅ Sử dụng static để đếm số tài khoản

┌─────────────────────────────────────────────────────────────┐
│ LỚP TAIKHOANNANGHANG │
├─────────────────────────────────────────────────────────────┤
│ │
│ 📦 FIELDS (Trường dữ liệu – Private) │
│ ├── _soTK : string (Số tài khoản – tự sinh) │
│ ├── _chuTK : string (Tên chủ tài khoản) │
│ ├── _soDu : decimal (Số dư) │
│ ├── _matKhau : string (Mật khẩu) │
│ └── _soLuongTK : static int (Đếm số TK đã tạo) │
│ │
│ 🔐 PROPERTIES (Thuộc tính) │
│ ├── SoTK { get; } (Read-only – tự sinh) │
│ ├── ChuTK { get; set; } (Có validation) │
│ └── SoDu { get; } (Read-only – chỉ xem) │
│ │
│ 🏗️ CONSTRUCTORS │
│ ├── TaiKhoanNganHang() (Mặc định – tự sinh số TK) │
│ └── TaiKhoanNganHang(chu, mk, du) (Có tham số) │
│ │
│ 🛠️ METHODS │
│ ├── HienThi() (Hiển thị thông tin) │
│ ├── NapTien(soTien) (Nạp tiền vào TK) │
│ ├── RutTien(soTien, mk) (Rút tiền – cần mật khẩu) │
│ └── DoiMatKhau(mkCu, mkMoi) (Đổi mật khẩu) │
│ │
└─────────────────────────────────────────────────────────────┘

BƯỚC 1: TẠO PROJECT MỚI

1.1. Mở Visual Studio

  • Mở Visual Studio 2022

1.2. Tạo Project mới

text
File → New → Project

Hoặc nhấn: Ctrl + Shift + N

1.3. Chọn loại Project

  • Gõ “Console” vào ô tìm kiếm

  • Chọn Console App (.NET Core) hoặc Console App (.NET Framework)

  • Nhấn Next

1.4. Đặt tên Project

text
Project name: Bai3_TaiKhoan
Location: D:\CSharp\LapTrinhHuongDoiTuong (hoặc thư mục của bạn)
Solution: LapTrinhHuongDoiTuong (chọn Add to Solution)
  • Nhấn Next

1.5. Chọn Framework

  • Chọn .NET 6.0 hoặc .NET 8.0 (LTS)

  • Nhấn Create

BƯỚC 2: TẠO CẤU TRÚC THƯ MỤC

2.1. Tạo thư mục Models

  1. Trong Solution Explorer, click chuột phải vào Project Bai3_TaiKhoan

  2. Chọn Add → New Folder

  3. Đặt tên: Models

  4. Nhấn Enter

BƯỚC 3: TẠO FILE LỚP TAIKHOANNANGHANG

3.1. Tạo file TaiKhoanNganHang.cs

  1. Click chuột phải vào thư mục Models

  2. Chọn Add → Class

  3. Đặt tên: TaiKhoanNganHang.cs

  4. Nhấn Add

BƯỚC 4: VIẾT CODE CHO LỚP TAIKHOANNANGHANG

4.1. Khai báo Namespace và Class

Mở file TaiKhoanNganHang.cs và viết:

csharp
using System;

namespace Bai3_TaiKhoan.Models
{
    public class TaiKhoanNganHang
    {
        // Code sẽ viết ở đây
    }
}

4.2. Khai báo Fields (Trường dữ liệu)

csharp
public class TaiKhoanNganHang
{
    // === FIELDS (Trường dữ liệu) ===
    private string _soTK;           // Số tài khoản (tự sinh)
    private string _chuTK;          // Tên chủ tài khoản
    private decimal _soDu;          // Số dư (dùng decimal cho tiền tệ)
    private string _matKhau;        // Mật khẩu
    private static int _soLuongTK = 0;  // Đếm số TK đã tạo (static)
}

Giải thích Fields:

 
 
FieldKiểuMục đíchLưu ý
_soTKstringSố tài khoảnTự sinh, không thay đổi
_chuTKstringTên chủ tài khoảnKiểm tra không rỗng
_soDudecimalSố dưDùng decimal cho tiền tệ
_matKhaustringMật khẩuBảo vệ giao dịch
_soLuongTKstatic intĐếm số TK đã tạoDùng chung

4.3. Khai báo Properties (Thuộc tính)

a. Property SoTK (Read-only – chỉ đọc)

csharp
public class TaiKhoanNganHang
{
    // ... Fields ở trên ...

    // === PROPERTIES ===
    
    // 1. Số tài khoản - Chỉ đọc, tự sinh
    public string SoTK
    {
        get { return _soTK; }
        // Không có set → Không thể thay đổi từ bên ngoài
    }
}

b. Property ChuTK (Có validation)

csharp
    // 2. Tên chủ tài khoản - Có kiểm tra không rỗng
    public string ChuTK
    {
        get { return _chuTK; }
        set
        {
            if (string.IsNullOrWhiteSpace(value))
                throw new ArgumentException("Tên chủ tài khoản không được để trống!");
            _chuTK = value.Trim();
        }
    }

c. Property SoDu (Read-only)

csharp
    // 3. Số dư - Chỉ đọc (không cho set trực tiếp)
    public decimal SoDu
    {
        get { return _soDu; }
        // Không có set → Chỉ thay đổi qua NapTien/RutTien
    }

4.4. Khai báo Constructors (Phương thức khởi tạo)

a. Constructor mặc định (Tự sinh số TK)

csharp
public class TaiKhoanNganHang
{
    // ... Fields và Properties ở trên ...

    // === CONSTRUCTORS ===

    // Constructor 1: Không tham số - Tự sinh số TK
    public TaiKhoanNganHang()
    {
        // Tăng số lượng TK lên 1
        _soLuongTK++;
        
        // Tự sinh số TK: TK001, TK002, TK003, ...
        _soTK = "TK" + _soLuongTK.ToString("D3");
        
        // Gán giá trị mặc định
        _chuTK = "Chưa xác định";
        _matKhau = "123456";        // Mật khẩu mặc định
        _soDu = 0;
    }
}

b. Constructor có tham số

csharp
    // Constructor 2: Có tham số
    public TaiKhoanNganHang(string chuTK, string matKhau, decimal soDu = 0) : this()
    {
        // this() gọi constructor mặc định để tự sinh số TK
        
        // Gán giá trị (có validation)
        ChuTK = chuTK;
        _matKhau = matKhau;
        _soDu = soDu >= 0 ? soDu : 0;  // Nếu số dư âm thì đặt về 0
    }

Giải thích:

  • : this() – Gọi constructor mặc định trước (để tự sinh số TK)

  • soDu = 0 – Tham số tùy chọn, mặc định là 0

  • Kiểm tra số dư không âm


4.5. Khai báo Methods (Phương thức)

a. Phương thức HienThi()

csharp
public class TaiKhoanNganHang
{
    // ... Fields, Properties, Constructors ở trên ...

    // === METHODS ===

    // 1. Hiển thị thông tin tài khoản
    public void HienThi()
    {
        Console.WriteLine("═══════════════════════════════════════");
        Console.WriteLine($"  Số TK        : {_soTK}");
        Console.WriteLine($"  Chủ TK       : {_chuTK}");
        Console.WriteLine($"  Số dư        : {_soDu:N0} VND");
        Console.WriteLine("═══════════════════════════════════════");
    }
}

b. Phương thức NapTien() – Nạp tiền

csharp
    // 2. Nạp tiền vào tài khoản
    public bool NapTien(decimal soTien)
    {
        // Kiểm tra số tiền nạp phải > 0
        if (soTien <= 0)
        {
            Console.WriteLine("❌ Số tiền nạp phải lớn hơn 0!");
            return false;
        }
        
        // Cộng thêm vào số dư
        _soDu += soTien;
        Console.WriteLine($"✓ Đã nạp {soTien:N0} VND. Số dư: {_soDu:N0} VND");
        return true;
    }

c. Phương thức RutTien() – Rút tiền

csharp
    // 3. Rút tiền từ tài khoản (cần mật khẩu)
    public bool RutTien(decimal soTien, string matKhau)
    {
        // Kiểm tra mật khẩu
        if (matKhau != _matKhau)
        {
            Console.WriteLine("❌ Mật khẩu sai!");
            return false;
        }
        
        // Kiểm tra số tiền rút phải > 0
        if (soTien <= 0)
        {
            Console.WriteLine("❌ Số tiền rút phải lớn hơn 0!");
            return false;
        }
        
        // Kiểm tra số dư có đủ không
        if (soTien > _soDu)
        {
            Console.WriteLine($"❌ Số dư không đủ! (Số dư: {_soDu:N0} VND)");
            return false;
        }
        
        // Trừ vào số dư
        _soDu -= soTien;
        Console.WriteLine($"✓ Đã rút {soTien:N0} VND. Số dư: {_soDu:N0} VND");
        return true;
    }

d. Phương thức DoiMatKhau() – Đổi mật khẩu

csharp
    // 4. Đổi mật khẩu
    public bool DoiMatKhau(string matKhauCu, string matKhauMoi)
    {
        // Kiểm tra mật khẩu cũ
        if (matKhauCu != _matKhau)
        {
            Console.WriteLine("❌ Mật khẩu cũ sai!");
            return false;
        }
        
        // Kiểm tra mật khẩu mới không được rỗng
        if (string.IsNullOrWhiteSpace(matKhauMoi))
        {
            Console.WriteLine("❌ Mật khẩu mới không được để trống!");
            return false;
        }
        
        // Kiểm tra mật khẩu mới tối thiểu 6 ký tự
        if (matKhauMoi.Length < 6)
        {
            Console.WriteLine("❌ Mật khẩu mới phải có ít nhất 6 ký tự!");
            return false;
        }
        
        // Đổi mật khẩu
        _matKhau = matKhauMoi;
        Console.WriteLine("✓ Đổi mật khẩu thành công!");
        return true;
    }

4.6. Code hoàn chỉnh của TaiKhoanNganHang.cs

csharp
using System;

namespace Bai3_TaiKhoan.Models
{
    public class TaiKhoanNganHang
    {
        // === FIELDS ===
        private string _soTK;
        private string _chuTK;
        private decimal _soDu;
        private string _matKhau;
        private static int _soLuongTK = 0;

        // === PROPERTIES ===
        
        // 1. Số tài khoản - Read-only
        public string SoTK => _soTK;

        // 2. Tên chủ tài khoản - Có validation
        public string ChuTK
        {
            get => _chuTK;
            set
            {
                if (string.IsNullOrWhiteSpace(value))
                    throw new ArgumentException("Tên chủ tài khoản không được để trống!");
                _chuTK = value.Trim();
            }
        }

        // 3. Số dư - Read-only
        public decimal SoDu => _soDu;

        // === CONSTRUCTORS ===
        
        // Constructor mặc định - Tự sinh số TK
        public TaiKhoanNganHang()
        {
            _soLuongTK++;
            _soTK = "TK" + _soLuongTK.ToString("D3");
            _chuTK = "Chưa xác định";
            _matKhau = "123456";
            _soDu = 0;
        }

        // Constructor có tham số
        public TaiKhoanNganHang(string chuTK, string matKhau, decimal soDu = 0) : this()
        {
            ChuTK = chuTK;
            _matKhau = matKhau;
            _soDu = soDu >= 0 ? soDu : 0;
        }

        // === METHODS ===
        
        // 1. Hiển thị thông tin
        public void HienThi()
        {
            Console.WriteLine("═══════════════════════════════════════");
            Console.WriteLine($"  Số TK        : {_soTK}");
            Console.WriteLine($"  Chủ TK       : {_chuTK}");
            Console.WriteLine($"  Số dư        : {_soDu:N0} VND");
            Console.WriteLine("═══════════════════════════════════════");
        }

        // 2. Nạp tiền
        public bool NapTien(decimal soTien)
        {
            if (soTien <= 0)
            {
                Console.WriteLine("❌ Số tiền nạp phải lớn hơn 0!");
                return false;
            }
            _soDu += soTien;
            Console.WriteLine($"✓ Đã nạp {soTien:N0} VND. Số dư: {_soDu:N0} VND");
            return true;
        }

        // 3. Rút tiền
        public bool RutTien(decimal soTien, string matKhau)
        {
            if (matKhau != _matKhau)
            {
                Console.WriteLine("❌ Mật khẩu sai!");
                return false;
            }
            if (soTien <= 0)
            {
                Console.WriteLine("❌ Số tiền rút phải lớn hơn 0!");
                return false;
            }
            if (soTien > _soDu)
            {
                Console.WriteLine($"❌ Số dư không đủ! (Số dư: {_soDu:N0} VND)");
                return false;
            }
            _soDu -= soTien;
            Console.WriteLine($"✓ Đã rút {soTien:N0} VND. Số dư: {_soDu:N0} VND");
            return true;
        }

        // 4. Đổi mật khẩu
        public bool DoiMatKhau(string matKhauCu, string matKhauMoi)
        {
            if (matKhauCu != _matKhau)
            {
                Console.WriteLine("❌ Mật khẩu cũ sai!");
                return false;
            }
            if (string.IsNullOrWhiteSpace(matKhauMoi))
            {
                Console.WriteLine("❌ Mật khẩu mới không được để trống!");
                return false;
            }
            if (matKhauMoi.Length < 6)
            {
                Console.WriteLine("❌ Mật khẩu mới phải có ít nhất 6 ký tự!");
                return false;
            }
            _matKhau = matKhauMoi;
            Console.WriteLine("✓ Đổi mật khẩu thành công!");
            return true;
        }
    }
}

BƯỚC 5: VIẾT CHƯƠNG TRÌNH KIỂM TRA (TEST)

5.1. Mở file Program.cs

Trong Solution Explorer, mở file Program.cs của Project Bai3_TaiKhoan.

5.2. Viết code test

csharp
using System;
using Bai3_TaiKhoan.Models;

namespace Bai3_TaiKhoan
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.OutputEncoding = System.Text.Encoding.UTF8;
            Console.WriteLine("===== BÀI TẬP 3: LỚP TÀI KHOẢN NGÂN HÀNG =====\n");

            // ============================================
            // TEST 1: Constructor mặc định
            // ============================================
            Console.WriteLine("1. Constructor mặc định:");
            TaiKhoanNganHang tk1 = new TaiKhoanNganHang();
            tk1.HienThi();

            // ============================================
            // TEST 2: Constructor có tham số
            // ============================================
            Console.WriteLine("\n2. Constructor có tham số:");
            TaiKhoanNganHang tk2 = new TaiKhoanNganHang(
                "Nguyễn Văn A",
                "123456",
                1000000
            );
            tk2.HienThi();

            // ============================================
            // TEST 3: Tạo thêm tài khoản (xem tự sinh số TK)
            // ============================================
            Console.WriteLine("\n3. Tạo thêm tài khoản:");
            TaiKhoanNganHang tk3 = new TaiKhoanNganHang("Trần Thị B", "abc123", 500000);
            TaiKhoanNganHang tk4 = new TaiKhoanNganHang("Lê Văn C", "xyz789");
            
            Console.WriteLine($"   Số TK3: {tk3.SoTK} - Chủ TK: {tk3.ChuTK}");
            Console.WriteLine($"   Số TK4: {tk4.SoTK} - Chủ TK: {tk4.ChuTK}");

            // ============================================
            // TEST 4: Nạp tiền
            // ============================================
            Console.WriteLine("\n4. Nạp tiền:");
            tk2.NapTien(500000);
            tk2.HienThi();

            // ============================================
            // TEST 5: Rút tiền (đúng mật khẩu)
            // ============================================
            Console.WriteLine("\n5. Rút tiền (đúng mật khẩu):");
            tk2.RutTien(300000, "123456");
            tk2.HienThi();

            // ============================================
            // TEST 6: Rút tiền (sai mật khẩu)
            // ============================================
            Console.WriteLine("\n6. Rút tiền (sai mật khẩu):");
            tk2.RutTien(100000, "sai_mat_khau");

            // ============================================
            // TEST 7: Rút tiền (vượt số dư)
            // ============================================
            Console.WriteLine("\n7. Rút tiền (vượt số dư):");
            tk2.RutTien(2000000, "123456");

            // ============================================
            // TEST 8: Rút tiền (số tiền <= 0)
            // ============================================
            Console.WriteLine("\n8. Rút tiền (số tiền <= 0):");
            tk2.RutTien(-50000, "123456");

            // ============================================
            // TEST 9: Đổi mật khẩu (đúng)
            // ============================================
            Console.WriteLine("\n9. Đổi mật khẩu (đúng):");
            tk2.DoiMatKhau("123456", "newpass123");

            // ============================================
            // TEST 10: Đổi mật khẩu (sai mật khẩu cũ)
            // ============================================
            Console.WriteLine("\n10. Đổi mật khẩu (sai mật khẩu cũ):");
            tk2.DoiMatKhau("wrong_old", "newpass456");

            // ============================================
            // TEST 11: Đổi mật khẩu (quá ngắn)
            // ============================================
            Console.WriteLine("\n11. Đổi mật khẩu (quá ngắn):");
            tk2.DoiMatKhau("newpass123", "123");

            // ============================================
            // TEST 12: Thông tin cuối cùng
            // ============================================
            Console.WriteLine("\n12. Thông tin cuối cùng của TK2:");
            tk2.HienThi();

            Console.WriteLine("\nNhấn phím bất kỳ để thoát...");
            Console.ReadKey();
        }
    }
}

BƯỚC 6: CHẠY CHƯƠNG TRÌNH

6.1. Build Project

  • Nhấn Ctrl + Shift + B để biên dịch

6.2. Chạy chương trình

  • Nhấn F5 để chạy (Debug mode)

  • Hoặc Ctrl + F5 để chạy không debug

KẾT QUẢ DỰ KIẾN

text
===== BÀI TẬP 3: LỚP TÀI KHOẢN NGÂN HÀNG =====

1. Constructor mặc định:
═══════════════════════════════════════
  Số TK        : TK001
  Chủ TK       : Chưa xác định
  Số dư        : 0 VND
═══════════════════════════════════════

2. Constructor có tham số:
═══════════════════════════════════════
  Số TK        : TK002
  Chủ TK       : Nguyễn Văn A
  Số dư        : 1,000,000 VND
═══════════════════════════════════════

3. Tạo thêm tài khoản:
   Số TK3: TK003 - Chủ TK: Trần Thị B
   Số TK4: TK004 - Chủ TK: Lê Văn C

4. Nạp tiền:
✓ Đã nạp 500,000 VND. Số dư: 1,500,000 VND
═══════════════════════════════════════
  Số TK        : TK002
  Chủ TK       : Nguyễn Văn A
  Số dư        : 1,500,000 VND
═══════════════════════════════════════

5. Rút tiền (đúng mật khẩu):
✓ Đã rút 300,000 VND. Số dư: 1,200,000 VND
═══════════════════════════════════════
  Số TK        : TK002
  Chủ TK       : Nguyễn Văn A
  Số dư        : 1,200,000 VND
═══════════════════════════════════════

6. Rút tiền (sai mật khẩu):
❌ Mật khẩu sai!

7. Rút tiền (vượt số dư):
❌ Số dư không đủ! (Số dư: 1,200,000 VND)

8. Rút tiền (số tiền <= 0):
❌ Số tiền rút phải lớn hơn 0!

9. Đổi mật khẩu (đúng):
✓ Đổi mật khẩu thành công!

10. Đổi mật khẩu (sai mật khẩu cũ):
❌ Mật khẩu cũ sai!

11. Đổi mật khẩu (quá ngắn):
❌ Mật khẩu mới phải có ít nhất 6 ký tự!

12. Thông tin cuối cùng của TK2:
═══════════════════════════════════════
  Số TK        : TK002
  Chủ TK       : Nguyễn Văn A
  Số dư        : 1,200,000 VND
═══════════════════════════════════════

Nhấn phím bất kỳ để thoát...