Système bancaire
Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy. Leçon 106 sur 107.
Défi
FacileConstruisons un système bancaire qui gère les comptes, les transactions et les opérations financières ! Tu vas créer un système robuste où l’intégrité des données est essentielle : les soldes des comptes ne doivent changer qu’au moyen de méthodes validées, et les erreurs comme les découverts ou les montants invalides doivent être gérées correctement.
Tu organiseras ton code dans cinq fichiers :
account.go: définis une interfaceTransactableavec les méthodesDeposit(amount float64) erroretWithdraw(amount float64) error. Crée ensuite deux types de comptes qui implémentent cette interface :Un
CheckingAccountavec les champs non exportésid,holderetbalance. Les comptes courants autorisent les retraits qui ramènent le solde exactement à zéro, mais pas en dessous.Un
SavingsAccountavec les mêmes champs non exportés, ainsi qu’un champminBalance. Les comptes d’épargne doivent maintenir un solde minimum de 100.0 : les retraits qui feraient passer le solde sous ce seuil doivent échouer.Les deux types de comptes ont besoin de constructeurs (
NewCheckingAccountetNewSavingsAccount) et d’une méthode getterBalance() float64. Pour les dépôts, refuse les montants négatifs ou nuls. Pour les retraits, refuse les montants négatifs ou nuls ainsi que les montants supérieurs aux fonds disponibles.transaction.go: crée une structureTransactionpour enregistrer l’activité des comptes. Chaque transaction possède unType(string : "deposit" ou "withdrawal"), unAmount(float64) et unAccountID(string). Ajoute un constructeurNewTransactionet une méthodeString() stringqui renvoie le format suivant :[Type] $[Amount] on [AccountID], avec le montant formaté avec deux décimales.bank.go: construis une structureBankqui gère plusieurs comptes et enregistre les transactions. Stocke les comptes dans une map indexée par ID et conserve une slice de transactions. Implémente :NewBank() *Bank: initialise des collections videsAddAccount(id string, account Transactable): enregistre un compteDeposit(accountID string, amount float64) error: effectue un dépôt sur un compte et enregistre la transaction en cas de succèsWithdraw(accountID string, amount float64) error: effectue un retrait sur un compte et enregistre la transaction en cas de succèsTransfer(fromID, toID string, amount float64) error: transfère de l’argent entre les comptes de manière atomique (si le retrait réussit mais que le dépôt échoue, annule le retrait)GetBalance(accountID string) (float64, error): renvoie le solde d’un compte
Renvoie les erreurs appropriées pour les comptes inexistants.
errors.go: définis les erreurs sentinelles pour tes opérations bancaires :ErrAccountNotFound: lorsqu’un ID de compte n’existe pasErrInsufficientFunds: lorsqu’un retrait dépasse le solde disponibleErrInvalidAmount: lorsque le montant d’un dépôt ou d’un retrait est nul ou négatifErrMinBalanceRequired: lorsqu’un retrait d’un compte d’épargne ferait passer le solde sous le minimum requis
main.go: crée une banque et traite les opérations en fonction de l’entrée.Lis le nombre de comptes à créer. Pour chaque compte, lis le type de compte (
checkingousavings), l’ID, le nom du titulaire et le solde initial. Crée le type de compte approprié et ajoute-le à la banque.Lis 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, affiche le résultat :
OKpour les dépôts/retraits/transferts réussis, le solde formaté avec deux décimales pour les requêtes de solde, ouError: [message]en cas d’échec, en utilisant les messages de tes erreurs sentinelles.
Les entrées suivantes seront fournies :
- Le nombre de comptes, puis pour chaque compte son type, son ID, son titulaire et son solde initial (4 lignes par compte)
- Le nombre d’opérations, puis chaque opération (1 ligne par opération)
Par exemple, pour :
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 ACC002Ta sortie doit être :
OK
700.00
Error: minimum balance required
Error: insufficient funds
OK
1000.00Et pour :
1
checking
C100
Charlie
100.00
4
withdraw C100 100
balance C100
deposit C100 -50
withdraw C999 50Ta sortie doit être :
OK
0.00
Error: invalid amount
Error: account not foundRemarque comment l’interface Transactable permet à la Bank de fonctionner uniformément avec les deux types de comptes, tandis que chaque type de compte applique ses propres règles. La méthode Transfer illustre les 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 les 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
1Fondamentaux de la POO en Go
Fichiers externesEspace de travail et modules GoPackages et importsNoms exportés et non exportésIntroduction à la POO en GoStructs comme classesDéfinir des méthodes sur des structsRécepteurs pointeurs ou par valeurInitialisation des structsFonctions constructeursRécapitulatif - Calculatrice simple4Interfaces
Introduction aux interfacesImplémentation impliciteL’interface comme contratInterface vide (any)Assertion de typeCommutation de typeComposition d’interfacesInterfaces Stringer et ErrorRécapitulatif - Calculateur de formes7Encapsulation
Champs exportés vs non exportésEncapsulation au niveau du packageMéthodes Getter et SetterDissimulation de l’information en GoRécapitulatif – Fiches d’étudiants10Génériques (Go 1.18+)
Introduction aux génériquesParamètres de typeContraintes de typeStructures génériquesSolution de contournement pour les méthodes génériquesRécapitulatif - Collection générique2Plongée approfondie dans les types et les structs
Types de base et compositesDéfinitions de types personnalisésTags de structStructs anonymesStructs imbriquésValeurs zéro et valeurs par défautRécapitulatif - Carnet de contacts5La composition plutôt que l’héritage
Pourquoi Go n’a pas d’héritageBases de l’inclusion de structsPromotion des méthodesInclure plusieurs structsInclusion ou agrégationMasquage des méthodes inclusesRécapitulatif : hiérarchie des employés8Gestion des erreurs et POO
L’interface errorTypes d’erreurs personnalisésEnrobage des erreurs (fmt.Errorf)Erreurs sentinelleserrors.Is() et errors.As()Panic, Defer et RecoverRécapitulatif - Analyseur de fichiers11Bibliothèque standard et POO
io.Reader et io.Writersort.InterfaceInterface fmt.Stringerencoding/json avec des structsInterface http.HandlerRécapitulatif - Modèles d’API REST14Modèles de conception – Partie 2
Modèle CommandeModèle AdaptateurModèle DécorateurModèle Méthode modèleModèle ÉtatModèle CompositeMiddleware comme décorateur3Pointeurs et mémoire
Notions de base des pointeurs en GoPointeurs vers des structuresPassage par valeur ou par référenceLa fonction new()Garbage collection en GoRécapitulatif - Constructeur de listes chaînées6Polymorphisme en Go
Polymorphisme via les interfacesDuck typing en GoRègles de satisfaction des interfacesCollections polymorphesInjection de dépendancesRécapitulatif – Processeur de paiements9Concurrence et POO
Bases des GoroutinesCanaux et communicationCanaux tamponnés ou non tamponnésInstruction selectsync.Mutex et sync.RWMutexsync.WaitGroupConception de structures thread-safeRécapitulatif - Pool de workersEntraînez-vous par vous-même : Compilateur Go en ligne