Sistema de préstamos
Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy — lección 100 de 107.
Desafío
Fácil¡Vamos a construir el sistema de préstamos para nuestro proyecto de Gestión de Biblioteca! Crearás una estructura Library que gestiona colecciones de libros y usuarios, con métodos para manejar las operaciones de préstamo y devolución, completando con la validación adecuada.
Organizarás tu código en cuatro archivos:
book.go: Tu estructuraBookde la lección anterior con los camposID,Title,Author,ISBNyAvailable. Incluye el constructorNewBookque inicializa los libros como disponibles.user.go: Tu estructuraUserconID,Name,EmailyBorrowedBooks(un slice de IDs de libros). Incluye el constructorNewUserque inicializa a los usuarios con una lista de préstamos vacía.library.go: Crea una estructuraLibraryque almacene libros y usuarios en mapas (indexados por sus IDs). Construye estos componentes:- Un constructor
NewLibraryque inicialice mapas vacíos para libros y usuarios - Un método
AddBookque añada un libro a la biblioteca - Un método
AddUserque añada un usuario a la biblioteca - Un método
Borrowque reciba un ID de usuario y un ID de libro, valide la operación, marque el libro como no disponible, añada el ID del libro a la lista de préstamos del usuario y devuelva un error si algo sale mal - Un método
Returnque revierta el proceso de préstamo: marque el libro como disponible y lo elimine de la lista de préstamos del usuario
Tu método
Borrowdebe devolver estos errores:user not foundsi el ID de usuario no existebook not foundsi el ID de libro no existebook not availablesi el libro ya está prestado
Tu método
Returndebe devolver estos errores:user not foundsi el ID de usuario no existebook not foundsi el ID de libro no existebook not borrowedsi el libro ya está disponible
- Un constructor
main.go: Une todo creando una biblioteca, añadiendo libros y usuarios, y luego procesando las operaciones de préstamo/devolución.Lee el número de libros, luego para cada libro lee su ID, título, autor e ISBN. A continuación, lee el número de usuarios, y para cada usuario lee su ID, nombre y correo electrónico. Luego lee el número de operaciones, donde cada operación es
borrow [userID] [bookID]oreturn [userID] [bookID].Para cada operación, imprime
OKsi tiene éxito, oError: [message]si falla.
Se proporcionarán las siguientes entradas:
- Número de libros, luego el ID, título, autor e ISBN de cada libro (cada uno en líneas separadas)
- Número de usuarios, luego el ID, nombre y correo electrónico de cada usuario (cada uno en líneas separadas)
- Número de operaciones, luego cada operación en una línea separada
Por ejemplo, dado:
2
B001
The Go Programming Language
Alan Donovan
978-0134190440
B002
Clean Code
Robert Martin
978-0132350884
1
U001
Alice Smith
alice@library.com
4
borrow U001 B001
borrow U001 B001
return U001 B001
borrow U002 B001Tu salida debería ser:
OK
Error: book not available
OK
Error: user not foundY dado:
1
B100
Design Patterns
Gang of Four
978-0201633610
2
U001
Bob Jones
bob@email.com
U002
Carol White
carol@email.com
3
borrow U001 B100
borrow U002 B100
return U001 B100Tu salida debería ser:
OK
Error: book not available
OKY dado:
1
B001
Go in Action
William Kennedy
978-1617291784
1
U001
Dave Miller
dave@test.com
2
return U001 B001
borrow U001 B999Tu salida debería ser:
Error: book not borrowed
Error: book not foundObserva cómo la Library actúa como el coordinador central: valida todas las operaciones antes de modificar el estado, asegurando que los libros y los usuarios se mantengan sincronizados. ¡El uso de receptores de puntero permite que tus métodos modifiquen los datos reales almacenados en los mapas!
Pruébalo tú mismo
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Leer el número de libros
var numBooks int
fmt.Scanln(&numBooks)
// TODO: Crear una nueva biblioteca
// TODO: Leer los detalles de cada libro (ID, Title, Author, ISBN en líneas separadas)
// y añadirlos a la biblioteca
for i := 0; i < numBooks; i++ {
id, _ := reader.ReadString('\n')
id = strings.TrimSpace(id)
title, _ := reader.ReadString('\n')
title = strings.TrimSpace(title)
author, _ := reader.ReadString('\n')
author = strings.TrimSpace(author)
isbn, _ := reader.ReadString('\n')
isbn = strings.TrimSpace(isbn)
// TODO: Crear el libro y añadirlo a la biblioteca
}
// Leer el número de usuarios
var numUsers int
fmt.Scanln(&numUsers)
// TODO: Leer los detalles de cada usuario (ID, Name, Email en líneas separadas)
// y añadirlos a la biblioteca
for i := 0; i < numUsers; i++ {
id, _ := reader.ReadString('\n')
id = strings.TrimSpace(id)
name, _ := reader.ReadString('\n')
name = strings.TrimSpace(name)
email, _ := reader.ReadString('\n')
email = strings.TrimSpace(email)
// TODO: Crear el usuario y añadirlo a la biblioteca
}
// Leer el número de operaciones
var numOps int
fmt.Scanln(&numOps)
// TODO: Procesar cada operación
// Formato: "borrow [userID] [bookID]" o "return [userID] [bookID]"
for i := 0; i < numOps; i++ {
line, _ := reader.ReadString('\n')
line = strings.TrimSpace(line)
parts := strings.Split(line, " ")
// TODO: Analizar la operación y llamar al método apropiado
// Imprimir "OK" en caso de éxito o "Error: [message]" en caso de fallo
}
}
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 Pool12Conceptos avanzados de POO
Patrón Functional OptionsPatrón Builder en GoEncadenamiento de métodosAlias de tipos vs. definicionesFundamentos de ReflectionDescripción general de generación de código15Proyecto: Gestión de bibliotecas
Descripción general y estructura del proyectoStructs de libros y usuarios