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 capaz de converter os dados da sua biblioteca para o formato JSON para salvá-los e carregá-los novamente 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,isbneavailable. Inclua seu construtorNewBook.user.go: sua structUsercom tags de struct JSON paraid,name,emaileborrowed_books. Inclua seu construtorNewUser.data.go: crie uma structLibraryDataque funcione como um objeto de transferência para a serialização JSON. Ela deve ter dois campos:Books(uma fatia de ponteiros para Book) eUsers(uma fatia de ponteiros para User), cada um com as tags JSON apropriadas (bookseusers).library.go: sua structLibrarycom mapas 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. Ela deve coletar todos os livros e usuários dos mapas em uma structLibraryDatae, em seguida, serializá-la.FromJSON(jsonStr string): recebe uma string JSON, faz o unmarshalling dela em uma structLibraryDatae preenche os mapas 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 e, em seguida, para cada livro, leia seu ID, título, autor e ISBN. Depois, leia o número de usuários e, para cada usuário, leia seu ID, nome e e-mail. Após preencher a biblioteca, chame
ToJSON()e imprima a string JSON resultante.
As seguintes entradas serão fornecidas:
- Número de livros e, em seguida, o ID, título, autor e ISBN de cada livro (cada um em uma linha separada)
- Número de usuários e, em seguida, o ID, nome e e-mail de cada usuário (cada um em uma linha separada)
Por exemplo, dada a entrada:
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 dada a entrada:
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 pelos mapas para construir suas fatias, adicione os livros na ordem: B001, B002 etc. (ordenados alfabeticamente por ID) e faça o mesmo com os usuários. Isso garante uma saída JSON consistente. Você pode usar sort.Strings nas chaves do mapa antes de iterar.
A struct LibraryData faz a ponte entre o armazenamento baseado em mapas e o formato baseado em arrays do JSON. Esse padrão de objeto de transferência é comum na serialização de 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 título do livro
// TODO: Ler o autor 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 nome do usuário
// TODO: Ler o e-mail do usuário
// TODO: Criar o usuário e adicioná-lo à 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 ExternosWorkspace e Módulos do GoPacotes e ImportsNomes Exportados vs. Não ExportadosIntrodução à OOP em GoStructs como ClassesDefinindo Métodos em StructsReceptores de Ponteiro vs. de ValorInicialização de StructsFunções ConstrutorasRecapitulação — Calculadora Simples4Interfaces
Introdução às InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Asserção de TipoSwitch de TipoComposição de InterfacesInterfaces Stringer e ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs. Não ExportadosEncapsulamento no Nível de PacoteMétodos Getters e SettersOcultação de Informações em GoRecapitulação - Registros de Alunos10Genéricos (Go 1.18+)
Introdução aos genéricosParâmetros de tipoRestrições de tipoStructs genéricasAlternativa para métodos genéricosRecapitulação - Coleção genérica13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão Abstract FactoryPadrão ObserverPadrão Strategy2Tipos e Structs em Profundidade
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosTags de StructStructs AnônimasStructs AninhadasValores Zero e PadrõesRecapitulação - Livro de Contatos5Composição em vez de herança
Por que Go não tem herançaNoções básicas de incorporação de structsPromoção de métodosIncorporação de várias structsIncorporação vs agregaçãoOcultação de métodos incorporadosRecapitulação - Hierarquia de funcionários8Tratamento de Erros e OOP
A interface errorTipos de Erro PersonalizadosEncapsulamento de Erros (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - Analisador de Arquivos3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs. ReferênciaA Função new()Coleta de Lixo em GoRecapitulação - Construtor de Lista Ligada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfacesColeções PolimórficasInjeção de DependênciasRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e comunicaçãoCanais com e sem bufferInstrução selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de structs thread-safeRevisão - Worker Pool12Conceitos Avançados de OOP
Padrão de Opções FuncionaisPadrão Builder em GoEncadeamento de MétodosAliases de Tipos vs. DefiniçõesNoções Básicas de ReflectionVisão Geral da Geração de Código15Projeto: Gerenciamento de Biblioteca
Visão geral e estrutura do projetoStructs de livros e usuáriosPratique por conta própria: Compilador de Go online