Menu
CoddyTech

Système bancaire

Fait partie de la section Programmation orientée objet du Journey GDScript de Coddy. Leçon 63 sur 65.

challenge icon

Défi

Difficile

Construis une banque avec deux types de comptes. Chaque opération renvoie un dictionnaire de résultat {"ok": bool, "message": String} ; le code fourni l’affiche sous la forme OK: MESSAGE ou Failed: MESSAGE. Tous les montants sont des float et chaque montant dans un message comporte deux décimales après un $.

Transaction dans transaction.gd : le constructeur prend kind ("deposit", "withdrawal" ou "interest") et amount. _to_string() renvoie le type avec une majuscule initiale, puis le montant : Deposit - $200.00. Une transaction ne stocke pas son compte.

Account dans account.gd est une classe @abstract :

  • Le constructeur prend account_number, owner_name et initial_balance. L’argent est stocké dans la variable privée _balance ; balance est une propriété en lecture seule dont le getter renvoie _balance. _history est un Array[Transaction], et get_history() la renvoie.
  • Deux méthodes abstraites : account_type() -> String et withdrawal_error(amount: float) -> String, qui renvoie la raison du refus d’un retrait, ou "".
  • deposit(amount) : un montant inférieur ou égal à 0 échoue avec Deposit amount must be positive. Sinon, la méthode ajoute l’argent, enregistre une transaction deposit et renvoie Deposited $A. New balance: $B.
  • withdraw(amount) : un montant inférieur ou égal à 0 échoue avec Withdrawal amount must be positive ; une valeur non vide renvoyée par withdrawal_error() provoque un échec avec ce texte. Sinon, la méthode retire l’argent, enregistre un withdrawal et renvoie Withdrew $A. New balance: $B, suivi de (Overdraft) lorsque le solde est désormais inférieur à 0.
  • _to_string() renvoie TYPE NUMBER (OWNER): $BALANCE.

SavingsAccount dans savings_account.gd étend Account, avec les constantes INTEREST_RATE = 0.02 et MIN_BALANCE = 100.0. Son type est Savings. Un retrait qui ferait passer le solde sous MIN_BALANCE est refusé avec Cannot withdraw below minimum balance of $100.00. apply_interest() ajoute balance * INTEREST_RATE, enregistre une transaction interest et renvoie Applied interest: $I. New balance: $B.

CheckingAccount dans checking_account.gd étend Account, avec la constante OVERDRAFT_LIMIT = 200.0. Son type est Checking. Le solde peut descendre jusqu’à -200.00 ; un retrait qui le ferait descendre davantage est refusé avec Cannot exceed overdraft limit of $200.00.

Bank dans bank.gd stocke les comptes dans un dictionnaire privé indexé par numéro de compte :

  • Le constructeur prend bank_name.
  • create_account(kind, account_number, owner_name, initial_balance) est une fabrique : kind vaut savings ou checking, sans distinction de casse. L’opération échoue avec Account number already exists ou Invalid account type ; sinon, elle renvoie Savings account created successfully (ou Checking).
  • get_account(account_number) -> Account renvoie le compte, ou null.
  • transfer(from_number, to_number, amount) : l’opération échoue avec One or both accounts not found ; elle retire le montant du premier compte et, en cas d’échec, renvoie Transfer failed: suivi du message du retrait. Sinon, elle dépose le montant sur le deuxième compte et renvoie Transferred $A from FROM to TO.
  • total_holdings() -> float renvoie la somme de tous les soldes.

Le code fourni lit le nom de la banque, puis les commandes. Pour cette entrée :

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 sortie est :

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

Ton code va dans transaction.gd, account.gd, savings_account.gd, checking_account.gd et bank.gd. main.gd contient le code d’entrée/sortie fourni et ne peut pas être modifié.

Essayez vous-même

extends Node

func _ready():
	# Code d'entrée/sortie fourni : laissez-le tel quel

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

Toutes les leçons de Programmation orientée objet

Entraînez-vous par vous-même : Compilateur GDScript en ligne