Sistema bancario
Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 106 de 107.
Desafío
Fácil¡Construyamos un sistema bancario que administre cuentas, transacciones y operaciones financieras! Crearás un sistema sólido en el que la integridad de los datos es fundamental: los saldos de las cuentas solo deben cambiar mediante métodos validados, y los errores, como los descubiertos o los importes no válidos, deben gestionarse correctamente.
Organizarás tu código en cinco archivos:
account.go: Define una interfazTransactablecon los métodosDeposit(amount float64) erroryWithdraw(amount float64) error. Después, crea dos tipos de cuenta que implementen esta interfaz:Una
CheckingAccountcon los campos no exportadosid,holderybalance. Las cuentas corrientes permiten retiros que dejen el saldo exactamente en cero, pero no por debajo.Una
SavingsAccountcon los mismos campos no exportados, además de un campominBalance. Las cuentas de ahorro deben mantener un saldo mínimo de 100.0: los retiros que hicieran que el saldo bajara de este límite deben fallar.Ambos tipos de cuenta necesitan constructores (
NewCheckingAccountyNewSavingsAccount) y un método getterBalance() float64. Para los depósitos, rechaza los importes negativos o iguales a cero. Para los retiros, rechaza los importes negativos o iguales a cero y los importes que superen los fondos disponibles.transaction.go: Crea una estructuraTransactionpara registrar la actividad de las cuentas. Cada transacción tiene unType(string: "deposit" o "withdrawal"),Amount(float64) yAccountID(string). Incluye un constructorNewTransactiony un métodoString() stringque devuelva el formato:[Type] $[Amount] on [AccountID], con el importe formateado con dos decimales.bank.go: Crea una estructuraBankque administre varias cuentas y registre las transacciones. Almacena las cuentas en un mapa por ID y conserva un slice de transacciones. Implementa:NewBank() *Bank: inicializa colecciones vacíasAddAccount(id string, account Transactable): registra una cuentaDeposit(accountID string, amount float64) error: deposita en una cuenta y registra la transacción si la operación tiene éxitoWithdraw(accountID string, amount float64) error: retira de una cuenta y registra la transacción si la operación tiene éxitoTransfer(fromID, toID string, amount float64) error: mueve dinero entre cuentas de forma atómica (si el retiro tiene éxito, pero el depósito falla, revierte el retiro)GetBalance(accountID string) (float64, error): devuelve el saldo de una cuenta
Devuelve los errores apropiados para las cuentas inexistentes.
errors.go: Define errores centinela para tus operaciones bancarias:ErrAccountNotFound: cuando no existe un ID de cuentaErrInsufficientFunds: cuando el retiro supera el saldo disponibleErrInvalidAmount: cuando el importe del depósito o retiro es igual a cero o negativoErrMinBalanceRequired: cuando un retiro de una cuenta de ahorro incumpliría el saldo mínimo
main.go: Crea un banco y procesa operaciones según la entrada.Lee el número de cuentas que se crearán. Para cada cuenta, lee el tipo de cuenta (
checkingosavings), el ID, el nombre del titular y el saldo inicial. Crea el tipo de cuenta correspondiente y añádelo al banco.Después, lee el número de operaciones. Cada operación es una de las siguientes:
deposit [accountID] [amount]withdraw [accountID] [amount]transfer [fromID] [toID] [amount]balance [accountID]
Para cada operación, imprime el resultado:
OKpara depósitos, retiros o transferencias exitosos; el saldo formateado con dos decimales para las consultas de saldo; oError: [message]para los errores, utilizando los mensajes de error centinela.
Se proporcionarán las siguientes entradas:
- Número de cuentas y, después, el tipo, ID, titular y saldo inicial de cada cuenta (4 líneas por cuenta)
- Número de operaciones y, después, cada operación (1 línea por operación)
Por ejemplo, dada la siguiente entrada:
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 ACC002Tu salida debería ser:
OK
700.00
Error: minimum balance required
Error: insufficient funds
OK
1000.00Y dada la siguiente entrada:
1
checking
C100
Charlie
100.00
4
withdraw C100 100
balance C100
deposit C100 -50
withdraw C999 50Tu salida debería ser:
OK
0.00
Error: invalid amount
Error: account not foundObserva cómo la interfaz Transactable permite que Bank trabaje de manera uniforme con ambos tipos de cuenta, mientras que cada tipo de cuenta hace cumplir sus propias reglas. El método Transfer demuestra las operaciones atómicas: si algo sale mal durante el proceso, ¡el sistema mantiene su coherencia!
Pruébalo tú mismo
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Lee el número de cuentas
scanner.Scan()
numAccounts, _ := strconv.Atoi(scanner.Text())
// Crea un nuevo banco
bank := NewBank()
// Lee y crea las cuentas
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: Crea el tipo de cuenta apropiado basándote en accountType
// y añádelo al banco
_ = accountType
_ = id
_ = holder
_ = balance
}
// Lee el número de operaciones
scanner.Scan()
numOps, _ := strconv.Atoi(scanner.Text())
// Procesa cada operación
for i := 0; i < numOps; i++ {
scanner.Scan()
parts := strings.Fields(scanner.Text())
operation := parts[0]
// TODO: Maneja cada tipo de operación:
// - "deposit": deposita en la cuenta, imprime "OK" o error
// - "withdraw": retira de la cuenta, imprime "OK" o error
// - "transfer": transfiere entre cuentas, imprime "OK" o error
// - "balance": obtén e imprime el saldo formateado a 2 decimales
_ = operation
}
}
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de POO en Go
Archivos externosEspacio de trabajo y módulos de GoPaquetes e importacionesNombres exportados vs. no exportadosIntroducción a la POO en GoStructs como clasesDefinición de métodos en structsReceptores de puntero vs. de valorInicialización de structsFunciones constructorasResumen - Calculadora simple4Interfaces
Introducción a las interfacesImplementación implícitaLa interfaz como contratoInterfaz vacía (any)Type AssertionType SwitchComposición de interfacesInterfaces Stringer y ErrorResumen: Calculadora de figuras7Encapsulamiento
Campos exportados vs. no exportadosEncapsulamiento a nivel de paqueteMétodos Getter y SetterOcultamiento de información en GoResumen - Registros de estudiantes10Genéricos (Go 1.18+)
Introducción a los GenéricosParámetros de tipoRestricciones de tipoStructs genéricosSolución alternativa para métodos genéricosResumen - Colección genérica13Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón Abstract FactoryPatrón ObserverPatrón Strategy2Inmersión profunda en Tipos y Structs
Tipos básicos y compuestosDefiniciones de tipos personalizadosEtiquetas de StructsStructs anónimosStructs anidadosValores cero y por defectoRepaso - Libreta de contactos5Composición sobre herencia
Por qué Go no tiene herenciaConceptos básicos de incrustación de structsPromoción de métodosIncrustación de múltiples structsIncrustación vs AgregaciónShadowing de métodos incrustadosResumen - Jerarquía de empleados8Manejo de Errores y OOP
La interfaz errorTipos de errores personalizadosEnvoltura de errores (fmt.Errorf)Errores centinelaerrors.Is() y errors.As()Panic, Defer y RecoverResumen - Analizador de archivos3Punteros y Memoria
Fundamentos de punteros en GoPunteros a StructsPaso por valor vs referenciaLa función new()Garbage Collection en GoResumen - Constructor de Linked List6Polimorfismo en Go
Polimorfismo mediante interfacesDuck Typing en GoReglas de satisfacción de interfacesColecciones polimórficasInyección de dependenciasResumen - Procesador de pagos9Concurrencia y POO
Fundamentos de GoroutinesChannels y comunicaciónChannels con buffer vs. sin bufferSentencia Selectsync.Mutex y sync.RWMutexsync.WaitGroupDiseño de estructuras Thread-SafeResumen - Worker PoolPractica por tu cuenta: Compilador de Go online