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 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 interfaceTransactableavec les méthodesDeposit(amount float64) erroretWithdraw(amount float64) error. Créez ensuite deux types de comptes qui implémentent cette interface :Un
CheckingAccountavec des champs non exportésid,holder, etbalance. Les comptes chèques autorisent les retraits qui ramènent le solde à exactement zéro, mais pas en dessous.Un
SavingsAccountavec les mêmes champs non exportés plus un champminBalance. 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 (
NewCheckingAccountetNewSavingsAccount) et d'une méthode getterBalance() 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 structureTransactionpour enregistrer l'activité du compte. Chaque transaction possède unType(string : "deposit" ou "withdrawal"), unAmount(float64), et unAccountID(string). Incluez un constructeurNewTransactionet une méthodeString() stringqui retourne le format :[Type] $[Amount] on [AccountID]avec le montant formaté à deux décimales.bank.go: Construisez une structureBankqui 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 videsAddAccount(id string, account Transactable)— enregistre un compteDeposit(accountID string, amount float64) error— dépose sur un compte et enregistre la transaction en cas de succèsWithdraw(accountID string, amount float64) error— retire d'un compte et enregistre la transaction en cas de succèsTransfer(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 pasErrInsufficientFunds— lorsque le retrait dépasse le solde disponibleErrInvalidAmount— lorsque le montant du dépôt/retrait est nul ou négatifErrMinBalanceRequired— 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 (
checkingousavings), 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 :
OKpour les dépôts/retraits/transferts réussis, le solde formaté à deux décimales pour les demandes de solde, ouError: [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 ACC002Votre sortie devrait être :
OK
700.00
Error: minimum balance required
Error: insufficient funds
OK
1000.00Et étant donné :
1
checking
C100
Charlie
100.00
4
withdraw C100 100
balance C100
deposit C100 -50
withdraw C999 50Votre sortie devrait être :
OK
0.00
Error: invalid amount
Error: account not foundRemarquez 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
1Fondamentaux de la POO en Go
Fichiers externesEspace de travail et Modules GoPackages et ImportsNoms exportés vs non exportésIntroduction à la POO en GoLes Structs comme ClassesDéfinir des méthodes sur les StructsReceveurs par pointeur vs par valeurInitialisation de StructsFonctions constructeursRécapitulatif - Calculatrice simple4Interfaces
Introduction aux interfacesImplémentation impliciteL'interface comme contratInterface vide (any)Assertion de typeType SwitchComposition d'interfacesInterfaces Stringer & ErrorRécapitulatif - Calculateur de formes7Encapsulation
Champs exportés vs non exportésEncapsulation au niveau du packageMéthodes Getter & SetterMasquage d'informations en GoRécapitulatif - Dossiers étudiants10Génériques (Go 1.18+)
Introduction aux génériquesParamètres de typeContraintes de typeStructures génériquesContournement pour les méthodes génériquesRécapitulatif - Collections génériques13Patrons de conception, Partie 1
Introduction aux Design PatternsPatron SingletonPatron FactoryPatron Abstract FactoryPatron ObserverPatron Strategy2Exploration approfondie des Types et Structs
Types de base et compositesDéfinitions de types personnalisésTags de StructStructs anonymesStructs imbriquéesValeurs par défaut et Zero ValuesRécapitulatif - Carnet de contacts5Composition plutôt qu'héritage
Pourquoi Go n'a pas d'héritageLes bases de l'imbrication de structsPromotion de méthodesImbriquer plusieurs structsImbrication vs AgrégationMasquage de méthodes imbriquéesRécapitulatif - Hiérarchie des employés8Gestion des erreurs & POO
L'interface errorTypes d'erreurs personnalisésError Wrapping (fmt.Errorf)Erreurs sentinelleserrors.Is() et errors.As()Panic, Defer et RecoverRécapitulatif - File Parser11Bibliothèque standard et POO
io.Reader & io.WriterL'interface sort.InterfaceL'interface fmt.Stringerencoding/json avec les StructsL'interface http.HandlerRécapitulatif - Modèles d'API REST14Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositeMiddleware en tant que Décorateur3Pointeurs et Mémoire
Bases des pointeurs en GoPointeurs vers des structsPassage par valeur vs référenceLa fonction new()Garbage Collection en GoRécapitulatif - Constructeur de liste chaînée6Le polymorphisme en Go
Le polymorphisme via les interfacesLe Duck Typing en GoRègles de satisfaction des interfacesCollections polymorphesInjection de dépendancesRécapitulatif - Processeur de paiement9Concurrence et POO
Bases des GoroutinesChannels et CommunicationChannels avec buffer vs sans bufferL'instruction Selectsync.Mutex et sync.RWMutexsync.WaitGroupConception de structures Thread-SafeRécapitulatif - Worker Pool