JSON-Persistenzschicht
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy — Lektion 102 von 107.
Aufgabe
EinfachLassen wir uns eine Datenpersistenz zu unserem Bibliotheksverwaltungssystem hinzufügen! Sie werden eine JSON-Persistenzschicht implementieren, die die Daten Ihrer Bibliothek zum Speichern in das JSON-Format konvertieren und aus JSON-Strings wieder laden kann. Dies ist für jede reale Anwendung unerlässlich, die Daten zwischen Sitzungen erhalten muss.
Sie werden Ihren Code auf fünf Dateien verteilen:
book.go: IhrBook-Struct mit JSON-Struct-Tags zur Steuerung der Serialisierung. Jedes Feld sollte ein entsprechendes JSON-Tag haben:id,title,author,isbnundavailable. Fügen Sie IhrenNewBook-Konstruktor hinzu.user.go: IhrUser-Struct mit JSON-Struct-Tags fürid,name,emailundborrowed_books. Fügen Sie IhrenNewUser-Konstruktor hinzu.data.go: Erstellen Sie einLibraryData-Struct, das als Transferobjekt für die JSON-Serialisierung dient. Es sollte zwei Felder haben:Books(ein Slice von Book-Pointern) undUsers(ein Slice von User-Pointern), jeweils mit entsprechenden JSON-Tags (booksundusers).library.go: IhrLibrary-Struct mit Maps für Bücher und Benutzer. Fügen Sie zwei neue Methoden hinzu:ToJSON()— konvertiert die Daten der Bibliothek in einen formatierten JSON-String unter Verwendung vonjson.MarshalIndentmit einer Einrückung von zwei Leerzeichen. Es sollte alle Bücher und Benutzer aus den Maps in einemLibraryData-Struct sammeln und dieses dann serialisieren.FromJSON(jsonStr string)— nimmt einen JSON-String entgegen, unmarshalt ihn in einLibraryData-Struct und füllt die Maps der Bibliothek mit den geladenen Büchern und Benutzern.
main.go: Demonstrieren Sie die Persistenzschicht, indem Sie eine Bibliothek aufbauen und diese in JSON konvertieren.Lesen Sie die Anzahl der Bücher ein, dann für jedes Buch dessen ID, Titel, Autor und ISBN. Lesen Sie als Nächstes die Anzahl der Benutzer ein und für jeden Benutzer dessen ID, Name und E-Mail. Nachdem Sie die Bibliothek gefüllt haben, rufen Sie
ToJSON()auf und geben Sie den resultierenden JSON-String aus.
Die folgenden Eingaben werden bereitgestellt:
- Anzahl der Bücher, dann die ID, der Titel, der Autor und die ISBN jedes Buches (jeweils in separaten Zeilen)
- Anzahl der Benutzer, dann die ID, der Name und die E-Mail jedes Benutzers (jeweils in separaten Zeilen)
Zum Beispiel, gegeben:
2
B001
The Go Programming Language
Alan Donovan
978-0134190440
B002
Clean Code
Robert Martin
978-0132350884
1
U001
Alice Smith
alice@library.comIhre Ausgabe sollte wie folgt aussehen:
{
"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": []
}
]
}Und gegeben:
1
B100
Design Patterns
Gang of Four
978-0201633610
0Ihre Ausgabe sollte wie folgt aussehen:
{
"books": [
{
"id": "B100",
"title": "Design Patterns",
"author": "Gang of Four",
"isbn": "978-0201633610",
"available": true
}
],
"users": []
}Wichtig: Wenn Sie über Maps iterieren, um Ihre Slices zu erstellen, fügen Sie Bücher in der Reihenfolge: B001, B002 usw. hinzu (alphabetisch nach ID sortiert) und Benutzer entsprechend. Dies gewährleistet eine konsistente JSON-Ausgabe. Sie können sort.Strings auf den Map-Keys verwenden, bevor Sie iterieren.
Das LibraryData-Struct schließt die Lücke zwischen Ihrer Map-basierten Speicherung und dem Array-basierten Format von JSON. Dieses Transferobjekt-Muster ist üblich, wenn komplexe Datenstrukturen serialisiert werden!
Probier es selbst
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Eine neue Bibliothek erstellen
library := NewLibrary()
// Anzahl der Bücher lesen
numBooksStr, _ := reader.ReadString('\n')
numBooks, _ := strconv.Atoi(strings.TrimSpace(numBooksStr))
// TODO: Details jedes Buches lesen (ID, title, author, ISBN)
// und sie zur Bibliothek hinzufügen
for i := 0; i < numBooks; i++ {
// TODO: Buch-ID lesen
// TODO: Buchtitel lesen
// TODO: Buchautor lesen
// TODO: Buch-ISBN lesen
// TODO: Buch erstellen und zur Bibliothek hinzufügen
}
// Anzahl der Benutzer lesen
numUsersStr, _ := reader.ReadString('\n')
numUsers, _ := strconv.Atoi(strings.TrimSpace(numUsersStr))
// TODO: Details jedes Benutzers lesen (ID, name, email)
// und sie zur Bibliothek hinzufügen
for i := 0; i < numUsers; i++ {
// TODO: Benutzer-ID lesen
// TODO: Benutzernamen lesen
// TODO: Benutzer-E-Mail lesen
// TODO: Benutzer erstellen und zur Bibliothek hinzufügen
}
// TODO: Bibliothek in JSON konvertieren und ausgeben
fmt.Println(library.ToJSON())
}
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der Go OOP
Externe DateienGo Workspace & ModulePackages & ImportsExportierte vs. nicht-exportierte NamenEinführung in OOP in GoStructs als KlassenMethoden für Structs definierenPointer- vs. Value-ReceiverStruct-InitialisierungKonstruktor-FunktionenZusammenfassung – Einfacher Taschenrechner4Interfaces
Einführung in InterfacesImplizite ImplementierungInterface als VertragLeeres Interface (any)Type AssertionType SwitchInterface-KompositionStringer & Error InterfacesRückblick - Formen-Rechner7Kapselung
Exportierte vs. nicht exportierte FelderKapselung auf Paket-EbeneGetter- & Setter-MethodenInformation Hiding in GoZusammenfassung - Studierendendatensätze10Generics (Go 1.18+)
Einführung in GenericsTypparameterType ConstraintsGenerische StructsWorkaround für generische MethodenZusammenfassung – Generische Collection2Vertiefung: Typen & Structs
Basis- & zusammengesetzte TypenBenutzerdefinierte TypdefinitionenStruct TagsAnonyme StructsVerschachtelte StructsZero Values & StandardwerteZusammenfassung - Kontaktbuch5Komposition statt Vererbung
Warum Go keine Vererbung hatGrundlagen des Struct EmbeddingMethod PromotionEinbetten mehrerer StructsEmbedding vs. AggregationShadowing eingebetteter MethodenZusammenfassung – Mitarbeiter-Hierarchie8Fehlerbehandlung & OOP
Das error-InterfaceEigene FehlertypenError Wrapping (fmt.Errorf)Sentinel-Fehlererrors.Is() und errors.As()Panic, Defer und RecoverZusammenfassung – Datei-Parser3Zeiger & Speicher
Zeiger-Grundlagen in GoZeiger auf StructsWertübergabe vs. ReferenzübergabeDie new() FunktionGarbage Collection in GoWiederholung – Linked List Builder6Polymorphismus in Go
Polymorphismus über InterfacesDuck Typing in GoInterface-ErfüllungsregelnPolymorphe CollectionsDependency InjectionZusammenfassung – Payment Processor9Nebenläufigkeit & OOP
Goroutines GrundlagenChannels & KommunikationGepufferte vs. ungepufferte ChannelsSelect-Anweisungsync.Mutex & sync.RWMutexsync.WaitGroupThread-sicheres Struct-DesignZusammenfassung - Worker Pool12Fortgeschrittene OOP-Konzepte
Functional Options PatternBuilder-Pattern in GoMethodenverkettungTyp-Aliase vs. DefinitionenReflection-GrundlagenÜberblick zur Code-Generierung15Projekt: Bibliotheksverwaltung
Projektübersicht & StrukturBuch- und Benutzer-Structs