Menu
CoddyTech

银行系统

本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 85 课,共 87 课。

这个挑战要求你使用 OOP 原则构建一个模拟现实金融业务的银行系统。

你的系统应能处理不同类型的账户,例如 SavingsAccount 和 CheckingAccount,它们都继承自基础 Account 类。每种账户类型都有独特的行为:储蓄账户可能会赚取利息,而支票账户可能会提供透支保护。

想一想如何对交易进行建模。像 Transactable 这样的接口可以定义 deposit() 和 withdraw() 方法。可以考虑使用 InsufficientFundsException 等自定义异常,妥善处理无效操作。

Bank 类可以管理多个账户和客户,以此展示组合。你可以应用工厂模式来创建不同类型的账户,也可以使用观察者模式,在账户发生变化时通知客户。

重点学习封装,以保护余额和账号等敏感数据,并使用多态统一处理不同类型的账户。

challenge icon

挑战

简单

让我们构建一个完整的银行系统,展示你对 OOP 原则的掌握!你将创建一个包含不同账户类型、交易处理和完善异常管理的系统,并将代码组织在多个文件中。

你将把代码组织在 7 个文件中:

  • Transactable.java:创建一个接口,用于定义金融操作的规范。它应声明方法 deposit(double amount) 和 withdraw(double amount),两者都返回布尔值来表示操作是否成功。
  • InsufficientFundsException.java:创建一个继承自 Exception 的自定义异常。构造函数应接收尝试取款的金额和当前余额,并按格式 Insufficient funds: attempted [amount], available [balance] 创建消息。
  • Account.java:创建一个抽象基类,表示任意银行账户。添加 accountNumber(String)和 balance(double)两个私有字段、一个用于初始化这两个字段的构造函数、适当的 getter、一个受保护的余额 setter(以便子类可以修改余额),以及一个返回 String 的抽象方法 getAccountType()。实现方法 getDetails(),使其返回 "[accountNumber] ([accountType]): $[balance]",其中余额保留 2 位小数。
  • SavingsAccount.java:创建一个继承 Account 并实现 Transactable 的类。添加一个 interestRate(double)私有字段。构造函数接收 accountNumber、初始余额和 interestRate。实现 getAccountType(),使其返回 "Savings"。对于 deposit(),将金额加到余额上并返回 true。对于 withdraw(),如果金额超过余额,则返回 false;否则扣除该金额并返回 true。添加方法 applyInterest(),按 balance * interestRate 的值增加余额(利率以小数形式存储,因此 0.05 表示 5%)。
  • CheckingAccount.java:创建一个继承 Account 并实现 Transactable 的类。添加一个 overdraftLimit(double)私有字段。构造函数接收 accountNumber、初始余额和 overdraftLimit。实现 getAccountType(),使其返回 "Checking"。对于 deposit(),将金额加到余额上并返回 true。对于 withdraw(),如果金额小于或等于余额加 overdraftLimit,则允许取款;如果金额超过此限额,则返回 false。
  • Bank.java:创建一个使用 ArrayList 管理账户的类。添加以下方法:
    • addAccount(Account account):将账户添加到银行
    • findAccount(String accountNumber):返回 Account;如果未找到,则返回 null
    • transfer(String fromAccount, String toAccount, double amount):在账户之间转账;如果源账户余额不足,则抛出 InsufficientFundsException。成功时,返回 "Transferred $[amount] from [fromAccount] to [toAccount]"
    • getTotalDeposits():返回所有账户余额的总和
  • Main.java:构建你的银行系统!你会收到一个以逗号分隔的命令字符串:
    • SAVINGS:accountNumber:balance:interestRate
    • CHECKING:accountNumber:balance:overdraftLimit
    • DEPOSIT:accountNumber:amount
    • WITHDRAW:accountNumber:amount
    • TRANSFER:fromAccount:toAccount:amount
    • INTEREST:accountNumber

    处理每条命令并打印:

    • SAVINGS/CHECKING:Account created: [accountNumber]
    • DEPOSIT:Deposited $[amount] to [accountNumber]
    • WITHDRAW:成功时打印 Withdrew $[amount] from [accountNumber],否则打印 Withdrawal failed: [accountNumber]
    • TRANSFER:打印成功消息,或打印 Transfer failed: [exception message]
    • INTEREST:Interest applied to [accountNumber]

    处理完所有命令后,打印 --- Bank Summary ---,然后打印每个账户的详情(使用 getDetails()),最后打印 Total deposits: $[total],并将总额格式化为 2 位小数。

你会收到一个输入:以逗号分隔的命令字符串。

例如,输入为 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 时,输出将为:

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.50

注意,尽管支票账户的余额只有 $500,它仍允许取出 $600:这就是透支保护的作用!储蓄账户会在转账后按余额赚取 5% 的利息。这个挑战将继承、接口、多态、自定义异常和封装结合起来,构建出一个真实的银行应用!

亲手试试

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: 创建一个 Bank 实例
        
        // TODO: 按逗号拆分 input,得到各条命令
        
        // TODO: 处理每条命令:
        // - SAVINGS:accountNumber:balance:interestRate -> 创建 SavingsAccount,打印 "Account created: [accountNumber]"
        // - CHECKING:accountNumber:balance:overdraftLimit -> 创建 CheckingAccount,打印 "Account created: [accountNumber]"
        // - DEPOSIT:accountNumber:amount -> 存款并打印 "Deposited $[amount] to [accountNumber]"
        // - WITHDRAW:accountNumber:amount -> 取款,并打印成功信息或 "Withdrawal failed: [accountNumber]"
        // - TRANSFER:fromAccount:toAccount:amount -> 转账,并打印成功信息或 "Transfer failed: [exception message]"
        // - INTEREST:accountNumber -> 计算利息并打印 "Interest applied to [accountNumber]"
        
        // TODO: 处理完所有命令后,打印 "--- Bank Summary ---"
        
        // TODO: 使用 getDetails() 打印每个账户的详细信息
        
        // TODO: 将 "Total deposits: $[total]" 格式化为保留 2 位小数后打印
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Java 在线编译器