Menu
CoddyTech

银行系统

本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 63 课,共 65 课。

challenge icon

挑战

困难

构建一个包含两种账户的银行。每个操作都会返回一个结果字典 {"ok": bool, "message": String};提供的代码会将其打印为 OK: MESSAGE 或 Failed: MESSAGE。所有金额都是 float,消息中的每个金额都会在 $ 后保留两位小数。

transaction.gd 中的 Transaction:构造函数接收 kind("deposit"、"withdrawal" 或 "interest")和 amount。_to_string() 会返回首字母大写的类型,后面接金额:Deposit - $200.00。交易不会存储所属账户。

account.gd 中的 Account 是一个 @abstract 类:

  • 构造函数接收 account_number、owner_name 和 initial_balance。金额保存在私有变量 _balance 中;balance 是只读属性,其 getter 会返回 _balance。_history 是一个 Array[Transaction],get_history() 会返回它。
  • 两个抽象方法:account_type() -> String 和 withdrawal_error(amount: float) -> String。后者会返回拒绝取款的原因,或者返回 ""。
  • deposit(amount):金额为 0 或更少时,会因 Deposit amount must be positive 而失败。否则会存入金额、记录一笔 deposit 交易,并返回 Deposited $A. New balance: $B。
  • withdraw(amount):金额为 0 或更少时,会因 Withdrawal amount must be positive 而失败;如果 withdrawal_error() 返回非空字符串,则会因该文本而失败。否则会取出金额、记录一笔 withdrawal 交易,并返回 Withdrew $A. New balance: $B;如果此时余额低于 0,后面还会加上 (Overdraft)。
  • _to_string() 会返回 TYPE NUMBER (OWNER): $BALANCE。

savings_account.gd 中的 SavingsAccount 继承自 Account,包含常量 INTEREST_RATE = 0.02 和 MIN_BALANCE = 100.0。其类型为 Savings。如果取款会使余额低于 MIN_BALANCE,则会因 Cannot withdraw below minimum balance of $100.00 而被拒绝。apply_interest() 会增加 balance * INTEREST_RATE,记录一笔 interest 交易,并返回 Applied interest: $I. New balance: $B。

checking_account.gd 中的 CheckingAccount 继承自 Account,包含常量 OVERDRAFT_LIMIT = 200.0。其类型为 Checking。余额最低可以降到 -200.00;如果取款会使余额更低,则会因 Cannot exceed overdraft limit of $200.00 而被拒绝。

bank.gd 中的 Bank 会将账户保存在一个以账户号码为键的私有字典中:

  • 构造函数接收 bank_name。
  • create_account(kind, account_number, owner_name, initial_balance) 是一个工厂方法:kind 可以是任意大小写形式的 savings 或 checking。如果账户号码已存在,会因 Account number already exists 而失败;如果账户类型无效,会因 Invalid account type 而失败。否则会返回 Savings account created successfully(或 Checking)。
  • get_account(account_number) -> Account 会返回该账户,或者返回 null。
  • transfer(from_number, to_number, amount):如果找不到一个或两个账户,则会因 One or both accounts not found 而失败;它会从第一个账户取款,如果取款失败,则会以 Transfer failed: 加上取款操作的消息作为失败信息。否则会将金额存入第二个账户,并返回 Transferred $A from FROM to TO。
  • total_holdings() -> float 会返回所有余额的总和。

提供的代码会读取银行名称,然后读取命令。对于以下输入:

First Bank
open savings|S1|Alice|1000
open checking|C1|Bob|50
withdraw S1|950
transfer S1|C1|300
withdraw C1|400
history C1
total

输出为:

OK: Savings account created successfully
OK: Checking account created successfully
Failed: Cannot withdraw below minimum balance of $100.00
OK: Transferred $300.00 from S1 to C1
OK: Withdrew $400.00. New balance: $-50.00 (Overdraft)
History of C1:
1. Deposit - $300.00
2. Withdrawal - $400.00
Total held by First Bank: $650.00

请将代码写在 transaction.gd、account.gd、savings_account.gd、checking_account.gd 和 bank.gd 中。main.gd 存放了提供的输入/输出代码,不能编辑。

亲手试试

extends Node

func _ready():
	# 已提供的输入/输出代码:保持原样。

	var bank := Bank.new(OS.read_string_from_stdin())

	var line := OS.read_string_from_stdin()
	while line != "":
		var parts := line.split(" ", true, 1)
		var f: PackedStringArray = parts[1].split("|") if parts.size() > 1 else PackedStringArray()
		match parts[0]:
			"open":
				show_result(bank.create_account(f[0], f[1], f[2], float(f[3])))
			"deposit":
				show_result(bank.get_account(f[0]).deposit(float(f[1])))
			"withdraw":
				show_result(bank.get_account(f[0]).withdraw(float(f[1])))
			"interest":
				var account: Account = bank.get_account(f[0])
				if account is SavingsAccount:
					var savings := account as SavingsAccount
					show_result(savings.apply_interest())
				else:
					print("Failed: ", f[0], " is not a savings account")
			"transfer":
				show_result(bank.transfer(f[0], f[1], float(f[2])))
			"history":
				var history: Array = bank.get_account(f[0]).get_history()
				print("History of ", f[0], ":")
				for i in history.size():
					print(i + 1, ". ", history[i])
			"account":
				print(bank.get_account(f[0]))
			"total":
				print("Total held by %s: $%.2f" % [bank.bank_name, bank.total_holdings()])

		line = OS.read_string_from_stdin()

func show_result(result: Dictionary) -> void:
	print(("OK: " if result["ok"] else "Failed: ") + result["message"])

面向对象编程中的所有课

自己练习: GDScript 在线编译器