Menu
CoddyTech

Hệ thống ngân hàng

Thuộc phần Lập trình hướng đối tượng trong hành trình C++ của Coddy. Bài học 104 trên 104.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống ngân hàng minh họa mẫu State, tính kế thừa và cách quản lý con trỏ thông minh. Bạn sẽ tạo một hệ thống trong đó các tài khoản có thể ở những trạng thái khác nhau (Active, Frozen, Closed), mỗi trạng thái có cách xử lý giao dịch riêng.

Bạn sẽ sắp xếp code trong sáu tệp:

  • AccountState.h: Xây dựng cơ sở hạ tầng cho mẫu State để quản lý các trạng thái tài khoản.

    Tạo một lớp cơ sở trừu tượng AccountState với các phương thức thuần ảo:

    • deposit(double amount): trả về true nếu cho phép gửi tiền, nếu không thì trả về false
    • withdraw(double amount): trả về true nếu cho phép rút tiền, nếu không thì trả về false
    • getStateName(): trả về tên trạng thái dưới dạng chuỗi

    Triển khai ba trạng thái cụ thể:

    • ActiveState: Cho phép gửi và rút tiền, trả về "Active"
    • FrozenState: Cho phép gửi tiền nhưng từ chối rút tiền, trả về "Frozen"
    • ClosedState: Từ chối cả gửi lẫn rút tiền, trả về "Closed"
  • Account.h: Xây dựng hệ thống phân cấp tài khoản có quản lý trạng thái.

    Tạo lớp cơ sở Account gồm:

    • Số tài khoản (chuỗi), tên chủ tài khoản và số dư
    • Một std::unique_ptr<AccountState> để quản lý trạng thái hiện tại
    • deposit(double amount): trước tiên kiểm tra trạng thái; nếu được phép thì cộng vào số dư và in ra "Deposited [amount] to [accountNumber]", nếu không thì in ra "Deposit rejected: account is [stateName]"
    • withdraw(double amount): kiểm tra trạng thái; nếu được phép và đủ tiền thì trừ tiền và in ra "Withdrew [amount] from [accountNumber]". Nếu trạng thái từ chối, hãy in ra "Withdrawal rejected: account is [stateName]". Nếu không đủ tiền, hãy in ra "Insufficient funds"
    • freeze(), activate() và close(): thay đổi trạng thái tài khoản
    • getInfo(): trả về "[accountNumber] ([ownerName]): $[balance] - [stateName]"
    • getAccountType() ảo, trả về "Basic"

    Tạo hai kiểu tài khoản dẫn xuất:

    • SavingsAccount: Có yêu cầu số dư tối thiểu (truyền vào hàm khởi tạo). Ghi đè withdraw để kiểm tra thêm xem việc rút tiền có làm số dư thấp hơn mức tối thiểu hay không; nếu có, hãy in ra "Cannot go below minimum balance of [minimum]". Trả về "Savings" cho kiểu tài khoản.
    • CheckingAccount: Có hạn mức thấu chi (truyền vào hàm khởi tạo). Cho phép rút tiền tối đa bằng (số dư + overdraftLimit). Trả về "Checking" cho kiểu tài khoản.
  • Transaction.h: Mô hình hóa giao dịch thành các đối tượng.

    Tạo lớp Transaction để ghi lại:

    • Loại giao dịch (chuỗi: "Deposit", "Withdrawal", "Transfer")
    • Số tiền
    • Số tài khoản liên quan
    • Trạng thái thành công (bool)

    Thêm phương thức getDescription() trả về "[type]: $[amount] on [accountNumber] - [Success/Failed]"

  • Customer.h: Tạo một khách hàng sở hữu nhiều tài khoản.

    Một Customer có tên, ID và một vector gồm các std::shared_ptr<Account>. Triển khai:

    • addAccount(std::shared_ptr<Account> account)
    • getAccount(const std::string& accountNumber): trả về tài khoản khớp hoặc nullptr
    • getTotalBalance(): tính tổng số dư của tất cả tài khoản
    • listAccounts(): in thông tin của từng tài khoản
  • Bank.h: Điều phối các hoạt động ngân hàng.

    Lớp Bank lưu trữ khách hàng và duy trì lịch sử giao dịch. Triển khai:

    • addCustomer(std::shared_ptr<Customer> customer)
    • findAccount(const std::string& accountNumber): tìm tài khoản trong tất cả khách hàng
    • processDeposit(const std::string& accountNumber, double amount): tìm tài khoản, thực hiện gửi tiền và ghi lại giao dịch
    • processWithdrawal(const std::string& accountNumber, double amount): tìm tài khoản, thực hiện rút tiền và ghi lại giao dịch
    • getTransactionCount(): trả về tổng số giao dịch đã xử lý
  • main.cpp: Minh họa hệ thống ngân hàng của bạn.

    Đọc bốn đầu vào:

    1. Thông tin khách hàng (định dạng: name,customerId)
    2. Thông tin tài khoản tiết kiệm (định dạng: accountNumber,minBalance)
    3. Thao tác 1 (định dạng: action,accountNumber,amount, trong đó action là deposit hoặc withdraw)
    4. Thao tác 2 (định dạng: action,accountNumber,amount hoặc freeze,accountNumber)

    Tạo ngân hàng và khách hàng. Tạo một tài khoản tiết kiệm với khách hàng làm chủ tài khoản rồi thêm tài khoản đó vào khách hàng. Thêm khách hàng vào ngân hàng. Thực hiện cả hai thao tác (nếu là lệnh freeze, hãy đóng băng tài khoản rồi thử rút một khoản nhỏ là $10 để minh họa trạng thái). Cuối cùng, in danh sách tài khoản của khách hàng và tổng số giao dịch theo định dạng "Transactions: [count]".

Ví dụ, với các đầu vào Alice,C001, SAV001,100, deposit,SAV001,500 và withdraw,SAV001,200:

Deposited 500 to SAV001
Withdrew 200 from SAV001
SAV001 (Alice): $300 - Active
Transactions: 2

Với các đầu vào Bob,C002, SAV002,50, deposit,SAV002,100 và freeze,SAV002:

Deposited 100 to SAV002
Withdrawal rejected: account is Frozen
SAV002 (Bob): $100 - Frozen
Transactions: 2

Với các đầu vào Carol,C003, SAV003,200, deposit,SAV003,250 và withdraw,SAV003,100:

Deposited 250 to SAV003
Cannot go below minimum balance of 200
SAV003 (Carol): $250 - Active
Transactions: 2

Thử thách này kết hợp mẫu State để quản lý hành vi tài khoản, tính kế thừa cho các kiểu tài khoản khác nhau, con trỏ thông minh để quản lý quan hệ sở hữu và theo dõi giao dịch: tất cả đều là những khái niệm cốt lõi bạn đã nắm vững trong suốt khóa học này.

Tự làm thử

#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include "Bank.h"

int main() {
    // Đọc đầu vào 1: thông tin khách hàng (định dạng: name,customerId)
    std::string customerInput;
    std::getline(std::cin, customerInput);
    
    // Đọc đầu vào 2: thông tin tài khoản tiết kiệm (định dạng: accountNumber,minBalance)
    std::string accountInput;
    std::getline(std::cin, accountInput);
    
    // Đọc đầu vào 3: thao tác 1 (định dạng: action,accountNumber,amount)
    std::string op1Input;
    std::getline(std::cin, op1Input);
    
    // Đọc đầu vào 4: thao tác 2 (định dạng: action,accountNumber,amount hoặc freeze,accountNumber)
    std::string op2Input;
    std::getline(std::cin, op2Input);
    
    // TODO: Phân tích thông tin khách hàng từ customerInput
    // Gợi ý: Dùng find(',') để tách chuỗi
    
    // TODO: Phân tích thông tin tài khoản từ accountInput
    
    // TODO: Tạo ngân hàng
    
    // TODO: Tạo khách hàng
    
    // TODO: Tạo tài khoản tiết kiệm do khách hàng sở hữu
    
    // TODO: Thêm tài khoản cho khách hàng
    
    // TODO: Thêm khách hàng vào ngân hàng
    
    // TODO: Phân tích cú pháp và xử lý thao tác 1
    // Định dạng: action,accountNumber,amount (action là "deposit" hoặc "withdraw")
    
    // TODO: Phân tích cú pháp và xử lý thao tác 2
    // Có thể là: action,accountNumber,amount hoặc freeze,accountNumber
    // Nếu là freeze, đóng băng tài khoản rồi thử rút $10
    
    // TODO: In ra danh sách tài khoản của khách hàng
    
    // TODO: In ra số lượng giao dịch theo dạng "Transactions: [count]"
    
    return 0;
}

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch C++ online