Camada de Persistência JSON
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy — lição 102 de 107.
Desafio
FácilVamos adicionar persistência de dados ao nosso Sistema de Gerenciamento de Biblioteca! Você implementará uma camada de persistência JSON que pode converter os dados da sua biblioteca para o formato JSON para salvar, e carregá-los de volta a partir de strings JSON. Isso é essencial para qualquer aplicação real que precise preservar dados entre sessões.
Você organizará seu código em cinco arquivos:
book.go: Sua structBookcom tags de struct JSON para controlar a serialização. Cada campo deve ter uma tag JSON correspondente:id,title,author,isbn, eavailable. Inclua seu construtorNewBook.user.go: Sua structUsercom tags de struct JSON paraid,name,email, eborrowed_books. Inclua seu construtorNewUser.data.go: Crie uma structLibraryDataque atue como um objeto de transferência para serialização JSON. Ela deve ter dois campos:Books(um slice de ponteiros para Book) eUsers(um slice de ponteiros para User), cada um com as tags JSON apropriadas (bookseusers).library.go: Sua structLibrarycom maps para livros e usuários. Adicione dois novos métodos:ToJSON()— converte os dados da biblioteca em uma string JSON formatada usandojson.MarshalIndentcom indentação de dois espaços. Ele deve coletar todos os livros e usuários dos maps em uma structLibraryDatae, em seguida, serializá-la.FromJSON(jsonStr string)— recebe uma string JSON, faz o unmarshal em uma structLibraryDatae popula os maps da biblioteca com os livros e usuários carregados.
main.go: Demonstre a camada de persistência construindo uma biblioteca e convertendo-a para JSON.Leia o número de livros, então, para cada livro, leia seu ID, título, autor e ISBN. Em seguida, leia o número de usuários e, para cada usuário, leia seu ID, nome e e-mail. Após popular a biblioteca, chame
ToJSON()e imprima a string JSON resultante.
As seguintes entradas serão fornecidas:
- Número de livros, depois o ID, título, autor e ISBN de cada livro (cada um em linhas separadas)
- Número de usuários, depois o ID, nome e e-mail de cada usuário (cada um em linhas separadas)
Por exemplo, dado:
2
B001
The Go Programming Language
Alan Donovan
978-0134190440
B002
Clean Code
Robert Martin
978-0132350884
1
U001
Alice Smith
alice@library.comSua saída deve ser:
{
"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 dado:
1
B100
Design Patterns
Gang of Four
978-0201633610
0Sua saída deve ser:
{
"books": [
{
"id": "B100",
"title": "Design Patterns",
"author": "Gang of Four",
"isbn": "978-0201633610",
"available": true
}
],
"users": []
}Importante: Ao iterar sobre os maps para construir seus slices, adicione os livros na ordem: B001, B002, etc. (ordenados por ID alfabeticamente) e os usuários de forma semelhante. Isso garante uma saída JSON consistente. Você pode usar sort.Strings nas chaves do map antes de iterar.
A struct LibraryData faz a ponte entre o seu armazenamento baseado em maps e o formato baseado em arrays do JSON. Este padrão de objeto de transferência é comum ao serializar estruturas de dados complexas!
Experimente você mesmo
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Criar uma nova biblioteca
library := NewLibrary()
// Ler o número de livros
numBooksStr, _ := reader.ReadString('\n')
numBooks, _ := strconv.Atoi(strings.TrimSpace(numBooksStr))
// TODO: Ler os detalhes de cada livro (ID, title, author, ISBN)
// e adicioná-los à biblioteca
for i := 0; i < numBooks; i++ {
// TODO: Ler o ID do livro
// TODO: Ler o title do livro
// TODO: Ler o author do livro
// TODO: Ler o ISBN do livro
// TODO: Criar o livro e adicionar à biblioteca
}
// Ler o número de usuários
numUsersStr, _ := reader.ReadString('\n')
numUsers, _ := strconv.Atoi(strings.TrimSpace(numUsersStr))
// TODO: Ler os detalhes de cada usuário (ID, name, email)
// e adicioná-los à biblioteca
for i := 0; i < numUsers; i++ {
// TODO: Ler o ID do usuário
// TODO: Ler o name do usuário
// TODO: Ler o email do usuário
// TODO: Criar o usuário e adicionar à biblioteca
}
// TODO: Converter a biblioteca para JSON e imprimi-la
fmt.Println(library.ToJSON())
}
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP em Go
Arquivos ExternosGo Workspace e MódulosPacotes e ImportaçõesNomes Exportados vs Não ExportadosIntrodução a OOP em GoStructs como ClassesDefinindo Métodos em StructsRecebedores de Ponteiro vs ValorInicialização de StructsFunções ConstrutorasRecapitulação - Calculadora Simples4Interfaces
Introdução a InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Type AssertionType SwitchComposição de InterfacesInterfaces Stringer & ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs Não ExportadosEncapsulamento em Nível de PacoteMétodos Getter e SetterOcultação de Informação em GoRecapitulação - Registros de Estudantes10Generics (Go 1.18+)
Introdução a GenericsParâmetros de TipoRestrições de TipoStructs GenéricasSolução Alternativa para Métodos GenéricosRecapitulação - Coleção Genérica2Mergulho Profundo em Tipos e Structs
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosStruct TagsStructs AnônimasStructs AninhadasZero Values e PadrõesRecapitulação - Agenda de Contatos5Composição em vez de Herança
Por que Go não possui HerançaFundamentos de Incorporação de StructsPromoção de MétodosIncorporando Múltiplas StructsIncorporação vs AgregaçãoShadowing de Métodos IncorporadosRecapitulação - Hierarquia de Funcionários8Tratamento de Erros e OOP
A Interface errorTipos de Erro PersonalizadosError Wrapping (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - File Parser3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs ReferênciaA Função new()Garbage Collection em GoRecapitulação - Construtor de Lista Encadeada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfaceColeções PolimórficasInjeção de DependênciaRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e ComunicaçãoCanais com Buffer vs. Sem BufferInstrução Selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de Structs Thread-SafeRecapitulação - Worker Pool12Conceitos Avançados de OOP
Padrão Functional OptionsPadrão Builder em GoEncadeamento de MétodosType Aliases vs DefiniçõesFundamentos de ReflectionVisão Geral de Geração de Código15Projeto: Gerenciamento de Biblioteca
Visão Geral e Estrutura do ProjetoStructs de Livro e Usuário