Menu
Coddy logo textTech

Système bancaire

Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy — leçon 106 sur 107.

challenge icon

Défi

Facile

Construisons un système bancaire qui gère des comptes, des transactions et des opérations financières ! Vous allez créer un système robuste où l'intégrité des données est critique — les soldes des comptes ne doivent changer que par des méthodes validées, et les erreurs comme les découverts ou les montants invalides doivent être gérées avec élégance.

Vous organiserez votre code sur cinq fichiers :

  • account.go : Définissez une interface Transactable avec les méthodes Deposit(amount float64) error et Withdraw(amount float64) error. Créez ensuite deux types de comptes qui implémentent cette interface :

    Un CheckingAccount avec des champs non exportés id, holder, et balance. Les comptes chèques autorisent les retraits qui ramènent le solde à exactement zéro, mais pas en dessous.

    Un SavingsAccount avec les mêmes champs non exportés plus un champ minBalance. Les comptes d'épargne doivent maintenir un solde minimum de 100.0 — les retraits qui feraient descendre le solde sous ce seuil doivent échouer.

    Les deux types de comptes ont besoin de constructeurs (NewCheckingAccount et NewSavingsAccount) et d'une méthode getter Balance() float64. Pour les dépôts, rejetez les montants négatifs ou nuls. Pour les retraits, rejetez les montants négatifs ou nuls ainsi que les montants dépassant les fonds disponibles.

  • transaction.go : Créez une structure Transaction pour enregistrer l'activité du compte. Chaque transaction possède un Type (string : "deposit" ou "withdrawal"), un Amount (float64), et un AccountID (string). Incluez un constructeur NewTransaction et une méthode String() string qui retourne le format : [Type] $[Amount] on [AccountID] avec le montant formaté à deux décimales.
  • bank.go : Construisez une structure Bank qui gère plusieurs comptes et enregistre les transactions. Stockez les comptes dans une map par ID et conservez une slice de transactions. Implémentez :
    • NewBank() *Bank — initialise des collections vides
    • AddAccount(id string, account Transactable) — enregistre un compte
    • Deposit(accountID string, amount float64) error — dépose sur un compte et enregistre la transaction en cas de succès
    • Withdraw(accountID string, amount float64) error — retire d'un compte et enregistre la transaction en cas de succès
    • Transfer(fromID, toID string, amount float64) error — déplace l'argent entre les comptes de manière atomique (si le retrait réussit mais que le dépôt échoue, annulez le retrait)
    • GetBalance(accountID string) (float64, error) — retourne le solde d'un compte

    Retournez les erreurs appropriées pour les comptes inexistants.

  • errors.go : Définissez des erreurs sentinelles pour vos opérations bancaires :
    • ErrAccountNotFound — lorsqu'un ID de compte n'existe pas
    • ErrInsufficientFunds — lorsque le retrait dépasse le solde disponible
    • ErrInvalidAmount — lorsque le montant du dépôt/retrait est nul ou négatif
    • ErrMinBalanceRequired — lorsqu'un retrait sur compte d'épargne violerait le solde minimum
  • main.go : Créez une banque et traitez les opérations basées sur l'entrée.

    Lisez le nombre de comptes à créer. Pour chaque compte, lisez le type de compte (checking ou savings), l'ID, le nom du titulaire et le solde initial. Créez le type de compte approprié et ajoutez-le à la banque.

    Lisez ensuite le nombre d'opérations. Chaque opération est l'une des suivantes :

    • deposit [accountID] [amount]
    • withdraw [accountID] [amount]
    • transfer [fromID] [toID] [amount]
    • balance [accountID]

    Pour chaque opération, affichez le résultat : OK pour les dépôts/retraits/transferts réussis, le solde formaté à deux décimales pour les demandes de solde, ou Error: [message] pour les échecs en utilisant vos messages d'erreur sentinelles.

Les entrées suivantes seront fournies :

  • Nombre de comptes, puis le type, l'ID, le titulaire et le solde initial de chaque compte (4 lignes chacun)
  • Nombre d'opérations, puis chaque opération (1 ligne chacune)

Par exemple, étant donné :

2
checking
ACC001
Alice
500.00
savings
ACC002
Bob
1000.00
6
deposit ACC001 200
balance ACC001
withdraw ACC002 950
withdraw ACC001 800
transfer ACC001 ACC002 100
balance ACC002

Votre sortie devrait être :

OK
700.00
Error: minimum balance required
Error: insufficient funds
OK
1000.00

Et étant donné :

1
checking
C100
Charlie
100.00
4
withdraw C100 100
balance C100
deposit C100 -50
withdraw C999 50

Votre sortie devrait être :

OK
0.00
Error: invalid amount
Error: account not found

Remarquez comment l'interface Transactable permet à la Banque de travailler avec les deux types de comptes de manière uniforme, tandis que chaque type de compte applique ses propres règles. La méthode Transfer démontre des opérations atomiques — si quelque chose se passe mal en cours de route, le système reste cohérent !

Essayez vous-même

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)

	// Lire le nombre de comptes
	scanner.Scan()
	numAccounts, _ := strconv.Atoi(scanner.Text())

	// Créer une nouvelle banque
	bank := NewBank()

	// Lire et créer les comptes
	for i := 0; i < numAccounts; i++ {
		scanner.Scan()
		accountType := scanner.Text()
		scanner.Scan()
		id := scanner.Text()
		scanner.Scan()
		holder := scanner.Text()
		scanner.Scan()
		balance, _ := strconv.ParseFloat(scanner.Text(), 64)

		// TODO: Créer le type de compte approprié en fonction de accountType
		// et l'ajouter à la banque
		_ = accountType
		_ = id
		_ = holder
		_ = balance
	}

	// Lire le nombre d'opérations
	scanner.Scan()
	numOps, _ := strconv.Atoi(scanner.Text())

	// Traiter chaque opération
	for i := 0; i < numOps; i++ {
		scanner.Scan()
		parts := strings.Fields(scanner.Text())
		operation := parts[0]

		// TODO: Gérer chaque type d'opération :
		// - "deposit" : déposer sur le compte, afficher "OK" ou une erreur
		// - "withdraw" : retirer du compte, afficher "OK" ou une erreur
		// - "transfer" : transférer entre comptes, afficher "OK" ou une erreur
		// - "balance" : obtenir et afficher le solde formaté à 2 décimales
		_ = operation
	}
}

Toutes les leçons de Programmation Orientée Objet