Livello di persistenza JSON
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 102 di 107.
Sfida
FacileAggiungiamo la persistenza dei dati al nostro sistema di gestione della biblioteca! Implementerai un livello di persistenza JSON in grado di convertire i dati della tua biblioteca in formato JSON per salvarli e di ricaricarli da stringhe JSON. È essenziale per qualsiasi applicazione reale che debba conservare i dati tra una sessione e l'altra.
Organizzerai il codice in cinque file:
book.go: la tua structBookcon tag JSON per la struct, che controllano la serializzazione. Ogni campo deve avere il tag JSON corrispondente:id,title,author,isbneavailable. Includi il costruttoreNewBook.user.go: la tua structUsercon tag JSON per la struct:id,name,emaileborrowed_books. Includi il costruttoreNewUser.data.go: crea una structLibraryDatache funga da oggetto di trasferimento per la serializzazione JSON. Deve avere due campi:Books(una slice di puntatori a Book) eUsers(una slice di puntatori a User), ciascuno con i tag JSON appropriati (bookseusers).library.go: la tua structLibrarycon map per libri e utenti. Aggiungi due nuovi metodi:ToJSON(): converte i dati della biblioteca in una stringa JSON formattata usandojson.MarshalIndentcon un'indentazione di due spazi. Deve raccogliere tutti i libri e gli utenti dalle map in una structLibraryData, quindi serializzarla.FromJSON(jsonStr string): prende una stringa JSON, la deserializza in una structLibraryDatae popola le map della biblioteca con i libri e gli utenti caricati.
main.go: mostra il livello di persistenza creando una biblioteca e convertendola in JSON.Leggi il numero di libri, poi per ogni libro leggi il suo ID, il titolo, l'autore e l'ISBN. Quindi leggi il numero di utenti e, per ogni utente, leggi il suo ID, il nome e l'indirizzo email. Dopo aver popolato la biblioteca, chiama
ToJSON()e stampa la stringa JSON risultante.
Verranno forniti i seguenti input:
- Numero di libri, poi ID, titolo, autore e ISBN di ciascun libro (ciascuno su una riga separata)
- Numero di utenti, poi ID, nome e indirizzo email di ciascun utente (ciascuno su una riga separata)
Per esempio, dati:
2
B001
The Go Programming Language
Alan Donovan
978-0134190440
B002
Clean Code
Robert Martin
978-0132350884
1
U001
Alice Smith
alice@library.comIl tuo output dovrebbe essere:
{
"books": [
{
"id": "B001",
"title": "The Go Programming Language",
"author": "Alan Donovan",
"isbn": "978-0134190440",
"available": true
},
{
"id": "B002",
"title": "Clean Code",
"author": "Robert Martin",
"isbn": "978-0132350884",
"available": true
}
],
"users": [
{
"id": "U001",
"name": "Alice Smith",
"email": "alice@library.com",
"borrowed_books": []
}
]
}E dati:
1
B100
Design Patterns
Gang of Four
978-0201633610
0Il tuo output dovrebbe essere:
{
"books": [
{
"id": "B100",
"title": "Design Patterns",
"author": "Gang of Four",
"isbn": "978-0201633610",
"available": true
}
],
"users": []
}Importante: quando iteri sulle map per creare le slice, aggiungi i libri nell'ordine B001, B002, ecc. (ordinati alfabeticamente per ID) e fai lo stesso per gli utenti. Questo garantisce un output JSON coerente. Puoi usare sort.Strings sulle chiavi della map prima di iterare.
La struct LibraryData colma il divario tra l'archiviazione basata su map e il formato basato su array di JSON. Questo schema dell'oggetto di trasferimento è comune quando si serializzano strutture dati complesse!
Provalo tu
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Crea una nuova biblioteca
library := NewLibrary()
// Leggi il numero di libri
numBooksStr, _ := reader.ReadString('\n')
numBooks, _ := strconv.Atoi(strings.TrimSpace(numBooksStr))
// TODO: Leggi i dettagli di ogni libro (ID, titolo, autore, ISBN)
// e aggiungili alla biblioteca
for i := 0; i < numBooks; i++ {
// TODO: Leggi l'ID del libro
// TODO: Leggi il titolo del libro
// TODO: Leggi l'autore del libro
// TODO: Leggi l'ISBN del libro
// TODO: Crea il libro e aggiungilo alla biblioteca
}
// Leggi il numero di utenti
numUsersStr, _ := reader.ReadString('\n')
numUsers, _ := strconv.Atoi(strings.TrimSpace(numUsersStr))
// TODO: Leggi i dettagli di ogni utente (ID, nome, email)
// e aggiungili alla biblioteca
for i := 0; i < numUsers; i++ {
// TODO: Leggi l'ID dell'utente
// TODO: Leggi il nome dell'utente
// TODO: Leggi l'email dell'utente
// TODO: Crea un utente e aggiungilo alla biblioteca
}
// TODO: Converti la biblioteca in JSON e stampala
fmt.Println(library.ToJSON())
}
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti di OOP in Go
File esterniWorkspace e moduli GoPacchetti e importazioniNomi esportati e non esportatiIntroduzione all’OOP in GoGli struct come classiDefinire metodi sugli structReceiver con puntatore vs receiver con valoreInizializzazione degli structFunzioni costruttriciRiepilogo - Calcolatrice semplice4Interfacce
Introduzione alle interfacceImplementazione implicitaL’interfaccia come contrattoInterfaccia vuota (any)Asserzione di tipoSwitch sul tipoComposizione di interfacceInterfacce Stringer ed ErrorRipasso - Calcolatore di forme7Incapsulamento
Campi esportati e non esportatiIncapsulamento a livello di packageMetodi Getter e SetterNascondimento delle informazioni in GoRiepilogo - Registri degli studenti10Tipi generici (Go 1.18+)
Introduzione ai tipi genericiParametri di tipoVincoli di tipoStruct genericheSoluzione alternativa per i metodi genericiRiepilogo - Collezione generica13Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello Abstract FactoryModello ObserverModello Strategy2Approfondimento su tipi e struct
Tipi di base e compostiDefinizioni di tipi personalizzatiTag delle structStruct anonimeStruct annidateValori zero e predefinitiRipasso - Rubrica5Composizione invece dell'ereditarietà
Perché Go non ha l'ereditarietàFondamenti dell'embedding delle structPromozione dei metodiEmbedding di più structEmbedding e aggregazione a confrontoMascheramento dei metodi embeddedRiepilogo: gerarchia dei dipendenti8Gestione degli errori e OOP
L'interfaccia errorTipi di errore personalizzatiWrapping degli errori (fmt.Errorf)Errori sentinellaerrors.Is() ed errors.As()Panic, Defer e RecoverRiepilogo - Parser di file11Libreria standard e OOP
io.Reader e io.Writersort.InterfaceInterfaccia fmt.Stringerencoding/json con le structInterfaccia http.HandlerRipasso - modelli REST API14Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeMiddleware come Decorator3Puntatori e memoria
Concetti base dei puntatori in GoPuntatori a structPassaggio per valore vs per riferimentoLa funzione new()Garbage collection in GoRiepilogo - Costruttore di liste concatenate6Polimorfismo in Go
Polimorfismo tramite interfacceDuck typing in GoRegole di soddisfacimento delle interfacceCollezioni polimorficheIniezione delle dipendenzeRiepilogo - Elaboratore di pagamenti9Concorrenza e OOP
Basi delle goroutineCanali e comunicazioneCanali bufferizzati vs non bufferizzatiIstruzione selectsync.Mutex e sync.RWMutexsync.WaitGroupProgettazione di struct thread-safeRiepilogo: worker pool12Concetti avanzati di OOP
Pattern delle opzioni funzionaliPattern Builder in GoConcatenamento dei metodiAlias di tipo e definizioni a confrontoNozioni di base sulla reflectionPanoramica sulla generazione del codice15Progetto: Gestione della biblioteca
Panoramica e struttura del progettoStruct per libri e utentiEsercitati da solo: Compilatore Go online