Menu
CoddyTech

Sistema bancario

Parte de la sección Programación orientada a objetos del Journey de GDScript de Coddy. Lección 63 de 65.

challenge icon

Desafío

Difícil

Crea un banco con dos tipos de cuentas. Cada operación devuelve un diccionario de resultado {"ok": bool, "message": String}; el código proporcionado lo imprime como OK: MESSAGE o Failed: MESSAGE. Todos los importes son float y cada importe en un mensaje tiene dos decimales después de un $.

Transaction en transaction.gd: el constructor recibe kind ("deposit", "withdrawal" o "interest") y amount. _to_string() devuelve el tipo con la primera letra en mayúscula, después el importe: Deposit - $200.00. Una transacción no almacena su cuenta.

Account en account.gd es una clase @abstract:

  • El constructor recibe account_number, owner_name e initial_balance. El dinero se guarda en _balance, que es privado; balance es una propiedad de solo lectura cuyo getter devuelve _balance. _history es un Array[Transaction], y get_history() lo devuelve.
  • Dos métodos abstractos: account_type() -> String y withdrawal_error(amount: float) -> String, que devuelve el motivo por el que se rechaza un retiro, o "".
  • deposit(amount): un importe de 0 o menos falla con Deposit amount must be positive. De lo contrario, añade el dinero, registra una transacción deposit y devuelve Deposited $A. New balance: $B.
  • withdraw(amount): un importe de 0 o menos falla con Withdrawal amount must be positive; un withdrawal_error() no vacío falla con ese texto. De lo contrario, retira el dinero, registra una transacción withdrawal y devuelve Withdrew $A. New balance: $B, seguido de (Overdraft) cuando el saldo queda por debajo de 0.
  • _to_string() devuelve TYPE NUMBER (OWNER): $BALANCE.

SavingsAccount en savings_account.gd extiende Account, con las constantes INTEREST_RATE = 0.02 y MIN_BALANCE = 100.0. Su tipo es Savings. Se rechaza un retiro que dejaría menos de MIN_BALANCE con Cannot withdraw below minimum balance of $100.00. apply_interest() añade balance * INTEREST_RATE, registra una transacción interest y devuelve Applied interest: $I. New balance: $B.

CheckingAccount en checking_account.gd extiende Account, con la constante OVERDRAFT_LIMIT = 200.0. Su tipo es Checking. El saldo puede bajar hasta -200.00; se rechaza un retiro que lo dejaría por debajo de ese valor con Cannot exceed overdraft limit of $200.00.

Bank en bank.gd guarda las cuentas en un diccionario privado cuya clave es el número de cuenta:

  • El constructor recibe bank_name.
  • create_account(kind, account_number, owner_name, initial_balance) es una fábrica: kind es savings o checking, sin importar las mayúsculas y minúsculas. Falla con Account number already exists o Invalid account type y, de lo contrario, devuelve Savings account created successfully (o Checking).
  • get_account(account_number) -> Account devuelve la cuenta o null.
  • transfer(from_number, to_number, amount): falla con One or both accounts not found; retira dinero de la primera cuenta y, si eso falla, falla con Transfer failed: seguido del mensaje del retiro. De lo contrario, deposita el dinero en la segunda cuenta y devuelve Transferred $A from FROM to TO.
  • total_holdings() -> float devuelve la suma de todos los saldos.

El código proporcionado lee el nombre del banco y después los comandos. Para esta entrada:

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

la salida es:

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

Tu código va en transaction.gd, account.gd, savings_account.gd, checking_account.gd y bank.gd. main.gd contiene el código de entrada/salida proporcionado y no se puede editar.

Pruébalo tú mismo

extends Node

func _ready():
	# Código de entrada/salida proporcionado: déjalo tal como está

	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"])

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de GDScript online