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 Java của Coddy. Bài học 85 trên 87.
Thử thách này yêu cầu bạn xây dựng một hệ thống ngân hàng mô phỏng các hoạt động tài chính trong thế giới thực bằng cách áp dụng các nguyên tắc OOP.
Hệ thống của bạn cần xử lý các loại tài khoản khác nhau như SavingsAccount và CheckingAccount, cả hai đều kế thừa lớp cơ sở Account. Mỗi loại tài khoản có hành vi riêng: tài khoản tiết kiệm có thể sinh lãi, còn tài khoản thanh toán có thể có hạn mức thấu chi.
Hãy nghĩ cách mô hình hóa các giao dịch. Một giao diện như Transactable có thể định nghĩa các phương thức deposit() và withdraw(). Bạn có thể dùng các ngoại lệ tùy chỉnh như InsufficientFundsException để xử lý các thao tác không hợp lệ một cách phù hợp.
Lớp Bank có thể quản lý nhiều tài khoản và khách hàng, qua đó thể hiện tính kết hợp. Bạn có thể áp dụng mẫu Factory để tạo các loại tài khoản khác nhau hoặc dùng mẫu Observer để thông báo cho khách hàng khi tài khoản thay đổi.
Tập trung vào tính đóng gói để bảo vệ dữ liệu nhạy cảm như số dư và số tài khoản, đồng thời dùng tính đa hình để xử lý thống nhất các loại tài khoản khác nhau.
Thử thách
DễHãy cùng xây dựng một hệ thống ngân hàng hoàn chỉnh để thể hiện bạn đã nắm vững các nguyên tắc OOP! Bạn sẽ tạo một hệ thống có nhiều loại tài khoản, xử lý giao dịch và quản lý ngoại lệ phù hợp, được sắp xếp trong nhiều tệp.
Bạn sẽ sắp xếp code trong bảy tệp:
Transactable.java: Tạo một giao diện định nghĩa quy ước cho các thao tác tài chính. Giao diện cần khai báo các phương thứcdeposit(double amount)vàwithdraw(double amount), cả hai đều trả về giá trị boolean để cho biết thao tác có thành công hay không.InsufficientFundsException.java: Tạo một ngoại lệ tùy chỉnh kế thừa từException. Hàm khởi tạo cần nhận số tiền rút đã thử và số dư hiện tại, rồi tạo thông báo theo định dạngInsufficient funds: attempted [amount], available [balance].Account.java: Tạo một lớp cơ sở trừu tượng đại diện cho mọi tài khoản ngân hàng. Thêm các trường riêng tư choaccountNumber(String) vàbalance(double), một hàm khởi tạo để khởi tạo cả hai, các hàm getter phù hợp, một hàm setter protected cho số dư để các lớp con có thể thay đổi, và một phương thức trừu tượnggetAccountType()trả về một String. Viết phương thứcgetDetails()trả về"[accountNumber] ([accountType]): $[balance]"với số dư được định dạng đến 2 chữ số thập phân.SavingsAccount.java: Tạo một lớp kế thừaAccountvà triển khaiTransactable. Thêm một trường riêng tưinterestRate(double). Hàm khởi tạo nhận accountNumber, số dư ban đầu và interestRate. Triển khaigetAccountType()để trả về"Savings". Vớideposit(), cộng số tiền vào số dư rồi trả về true. Vớiwithdraw(), nếu số tiền vượt quá số dư thì trả về false, nếu không thì trừ số tiền và trả về true. Thêm phương thứcapplyInterest()để tăng số dư thêmbalance * interestRate(tỷ lệ được lưu dưới dạng phân số, vì vậy0.05có nghĩa là 5%).CheckingAccount.java: Tạo một lớp kế thừaAccountvà triển khaiTransactable. Thêm một trường riêng tưoverdraftLimit(double). Hàm khởi tạo nhận accountNumber, số dư ban đầu và overdraftLimit. Triển khaigetAccountType()để trả về"Checking". Vớideposit(), cộng số tiền vào số dư rồi trả về true. Vớiwithdraw(), cho phép rút tiền nếu số tiền nhỏ hơn hoặc bằng số dư cộng overdraftLimit, nếu vượt quá giới hạn này thì trả về false.Bank.java: Tạo một lớp quản lý tài khoản bằng ArrayList. Thêm các phương thức:addAccount(Account account)- thêm một tài khoản vào ngân hàngfindAccount(String accountNumber)- trả về Account hoặc null nếu không tìm thấytransfer(String fromAccount, String toAccount, double amount)- chuyển tiền giữa các tài khoản, ném ngoại lệInsufficientFundsExceptionnếu tài khoản nguồn không đủ tiền. Nếu thành công, trả về"Transferred $[amount] from [fromAccount] to [toAccount]"getTotalDeposits()- trả về tổng số dư của tất cả tài khoản
Main.java: Xây dựng hệ thống ngân hàng của bạn! Bạn sẽ nhận một chuỗi lệnh phân tách bằng dấu phẩy:SAVINGS:accountNumber:balance:interestRateCHECKING:accountNumber:balance:overdraftLimitDEPOSIT:accountNumber:amountWITHDRAW:accountNumber:amountTRANSFER:fromAccount:toAccount:amountINTEREST:accountNumber
Xử lý từng lệnh và in ra:
- SAVINGS/CHECKING:
Account created: [accountNumber] - DEPOSIT:
Deposited $[amount] to [accountNumber] - WITHDRAW:
Withdrew $[amount] from [accountNumber]nếu thành công, hoặcWithdrawal failed: [accountNumber] - TRANSFER: In thông báo thành công hoặc
Transfer failed: [exception message] - INTEREST:
Interest applied to [accountNumber]
Sau khi xử lý tất cả lệnh, in
--- Bank Summary ---, rồi in thông tin chi tiết của từng tài khoản (dùnggetDetails()), cuối cùng inTotal deposits: $[total]với giá trị được định dạng đến 2 chữ số thập phân.
Bạn sẽ nhận một đầu vào: chuỗi lệnh phân tách bằng dấu phẩy.
Ví dụ, với đầu vào SAVINGS:SAV001:1000.00:0.05,CHECKING:CHK001:500.00:200.00,DEPOSIT:SAV001:250.00,WITHDRAW:CHK001:600.00,TRANSFER:SAV001:CHK001:100.00,INTEREST:SAV001, đầu ra sẽ là:
Account created: SAV001
Account created: CHK001
Deposited $250.00 to SAV001
Withdrew $600.00 from CHK001
Transferred $100.00 from SAV001 to CHK001
Interest applied to SAV001
--- Bank Summary ---
SAV001 (Savings): $1207.50
CHK001 (Checking): $0.00
Total deposits: $1207.50Lưu ý rằng tài khoản thanh toán cho phép rút $600 dù chỉ có số dư $500: đó là tác dụng của hạn mức thấu chi! Tài khoản tiết kiệm nhận lãi suất 5% trên số dư sau khi chuyển tiền. Thử thách này kết hợp kế thừa, giao diện, tính đa hình, ngoại lệ tùy chỉnh và tính đóng gói trong một ứng dụng ngân hàng thực tế!
Tự làm thử
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: Tạo một instance của Bank
// TODO: Tách đầu vào theo dấu phẩy để lấy từng lệnh
// TODO: Xử lý từng lệnh:
// - SAVINGS:accountNumber:balance:interestRate -> Tạo SavingsAccount, in ra "Account created: [accountNumber]"
// - CHECKING:accountNumber:balance:overdraftLimit -> Tạo CheckingAccount, in ra "Account created: [accountNumber]"
// - DEPOSIT:accountNumber:amount -> Gửi tiền và in ra "Deposited $[amount] to [accountNumber]"
// - WITHDRAW:accountNumber:amount -> Rút tiền và in ra thông báo thành công hoặc "Withdrawal failed: [accountNumber]"
// - TRANSFER:fromAccount:toAccount:amount -> Chuyển tiền và in ra thông báo thành công hoặc "Transfer failed: [exception message]"
// - INTEREST:accountNumber -> Tính lãi và in ra "Interest applied to [accountNumber]"
// TODO: Sau khi xử lý tất cả các lệnh, in ra "--- Bank Summary ---"
// TODO: In ra thông tin chi tiết của từng tài khoản bằng getDetails()
// TODO: In ra "Total deposits: $[total]" với 2 chữ số thập phân
}
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Kiến thức cơ bản về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTừ khóa thisPhương thứcTrường (thuộc tính)Phương thức khởi tạoNạp chồng phương thức khởi tạoÔn tập: Máy tính đơn giản4Kế thừa
Kế thừa cơ bản (extends)Từ khóa superGhi đè phương thức (@Override)Chuỗi gọi hàm khởi tạoLớp ObjectKế thừa đơn và đa cấpVì sao không hỗ trợ kế thừa nhiều lớpÔn tập: Phân cấp lớp Employee7Phương thức đặc biệt và lớp Object
Phương thức toString()equals() và hashCode()Phương thức clone()compareTo() và ComparableGiao diện ComparatorÔn tập: sắp xếp tùy chỉnh2Bộ điều chỉnh quyền truy cập và đóng gói
Tổng quan về các mức truy cậpPhương thức getter và setterẨn thông tinTừ khóa finalÔn tập: Trình quản lý tài khoản ngân hàng5Tính đa hình
Kiến thức cơ bản về nạp chồng phương thứcGhi đè phương thức (thời gian chạy)Chuyển kiểu lên và chuyển kiểu xuốngToán tử instanceofLớp và phương thức trừu tượngÔn tập: máy tính hình học8Khái niệm OOP nâng cao
Kết hợp và kế thừaKết tập và hợp thànhLớp bên trong, lớp lồng nhau và lớp ẩn danhKiểu enum và phương thức enumBản ghi (Java 16+)Lớp sealed (Java 17+)11Mẫu thiết kế phần 1
Giới thiệu về mẫu thiết kếMẫu SingletonMẫu FactoryMẫu BuilderMẫu ObserverMẫu Strategy14Thử thách cuối cùng
Nền tảng học trực tuyếnHệ thống ngân hàngPhát triển nhân vật trò chơiDịch vụ cho thuê phương tiện3Thuộc tính lớp và thành viên tĩnh
Biến của instance và biến tĩnhPhương thức tĩnhKhối tĩnhHằng số (static final)Ôn tập: bộ đếm và tiện ích6Giao diện và lớp trừu tượng
Giới thiệu về giao diệnTriển khai giao diệnTriển khai nhiều giao diệnPhương thức mặc định và tĩnh trong giao diệnLớp trừu tượng và giao diệnGiao diện hàmÔn tập: hệ thống thanh toán9Kiểu tổng quát
Giới thiệu về kiểu tổng quátLớp tổng quátPhương thức tổng quátTham số kiểu có giới hạnKý tự đại diện (?, extends, super)Ôn tập: vùng chứa tổng quát12Mẫu thiết kế, phần 2
Mẫu CommandMẫu AdapterMẫu DecoratorMẫu Template MethodMẫu StateMẫu CompositeMẫu IteratorTự luyện tập: Trình biên dịch Java online