Menu
CoddyTech

Lớp lưu trữ JSON

Thuộc phần Lập trình hướng đối tượng trong hành trình GO của Coddy. Bài học 102 trên 107.

challenge icon

Thử thách

Dễ

Hãy thêm khả năng lưu trữ dữ liệu vào hệ thống quản lý thư viện của chúng ta! Bạn sẽ triển khai một lớp lưu trữ JSON có thể chuyển đổi dữ liệu thư viện sang định dạng JSON để lưu lại, rồi tải dữ liệu từ chuỗi JSON. Đây là điều thiết yếu với mọi ứng dụng thực tế cần giữ lại dữ liệu giữa các phiên làm việc.

Bạn sẽ sắp xếp code trong năm tệp:

  • book.go: Struct Book của bạn với các thẻ JSON để kiểm soát quá trình tuần tự hóa. Mỗi trường cần có thẻ JSON tương ứng: id, title, author và available. Thêm hàm khởi tạo NewBook.
  • user.go: Struct User của bạn với các thẻ JSON cho id, name, email và borrowed_books. Thêm hàm khởi tạo NewUser.
  • data.go: Tạo struct LibraryData làm đối tượng trung gian cho quá trình tuần tự hóa JSON. Struct này cần có hai trường: Books (một lát cắt các con trỏ Book) và Users (một lát cắt các con trỏ User), mỗi trường có thẻ JSON phù hợp (books và users).
  • library.go: Struct Library của bạn với các bản đồ lưu sách và người dùng. Thêm hai phương thức mới:
    • ToJSON(): chuyển đổi dữ liệu của thư viện thành chuỗi JSON có định dạng bằng cách dùng json.MarshalIndent với thụt lề hai dấu cách. Phương thức này cần lấy tất cả sách và người dùng từ các bản đồ, đưa vào struct LibraryData, rồi tuần tự hóa struct đó.
    • FromJSON(jsonStr string): nhận một chuỗi JSON, giải tuần tự chuỗi đó thành struct LibraryData, rồi đưa sách và người dùng đã tải vào các bản đồ của thư viện.
  • main.go: Minh họa lớp lưu trữ bằng cách tạo một thư viện rồi chuyển đổi thư viện đó thành JSON.

    Đọc số lượng sách, sau đó đọc ID, tên sách, tác giả và ISBN của từng cuốn. Tiếp theo, đọc số lượng người dùng, rồi đọc ID, tên và email của từng người. Sau khi thêm dữ liệu vào thư viện, gọi ToJSON() và in ra chuỗi JSON thu được.

Đầu vào sẽ gồm:

  • Số lượng sách, sau đó là ID, tên sách, tác giả và ISBN của từng cuốn, mỗi giá trị nằm trên một dòng riêng
  • Số lượng người dùng, sau đó là ID, tên và email của từng người, mỗi giá trị nằm trên một dòng riêng

Ví dụ, với đầu vào:

2
B001
The Go Programming Language
Alan Donovan
978-0134190440
B002
Clean Code
Robert Martin
978-0132350884
1
U001
Alice Smith
alice@library.com

Đầu ra cần là:

{
  "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": []
    }
  ]
}

Với đầu vào:

1
B100
Design Patterns
Gang of Four
978-0201633610
0

Đầu ra cần là:

{
  "books": [
    {
      "id": "B100",
      "title": "Design Patterns",
      "author": "Gang of Four",
      "isbn": "978-0201633610",
      "available": true
    }
  ],
  "users": []
}

Quan trọng: Khi duyệt các bản đồ để tạo lát cắt, hãy thêm sách theo thứ tự B001, B002, v.v., sắp xếp theo thứ tự chữ cái của ID, và sắp xếp người dùng tương tự. Cách này giúp đầu ra JSON nhất quán. Bạn có thể dùng sort.Strings trên các khóa của bản đồ trước khi duyệt.

Struct LibraryData làm cầu nối giữa cách lưu trữ dựa trên bản đồ của bạn và định dạng dựa trên mảng của JSON. Mẫu đối tượng trung gian này thường được dùng khi tuần tự hóa các cấu trúc dữ liệu phức tạp!

Tự làm thử

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Tạo một thư viện mới
	library := NewLibrary()

	// Đọc số lượng sách
	numBooksStr, _ := reader.ReadString('\n')
	numBooks, _ := strconv.Atoi(strings.TrimSpace(numBooksStr))

	// TODO: Đọc thông tin của từng cuốn sách (ID, tiêu đề, tác giả, ISBN)
	// và thêm chúng vào thư viện
	for i := 0; i < numBooks; i++ {
		// TODO: Đọc ID của sách
		// TODO: Đọc tiêu đề sách
		// TODO: Đọc tên tác giả của sách
		// TODO: Đọc ISBN của sách
		// TODO: Tạo sách và thêm vào thư viện
	}

	// Đọc số lượng người dùng
	numUsersStr, _ := reader.ReadString('\n')
	numUsers, _ := strconv.Atoi(strings.TrimSpace(numUsersStr))

	// TODO: Đọc thông tin của từng người dùng (ID, tên, email)
	// và thêm chúng vào thư viện
	for i := 0; i < numUsers; i++ {
		// TODO: Đọc ID của người dùng
		// TODO: Đọc tên người dùng
		// TODO: Đọc email người dùng
		// TODO: Tạo người dùng và thêm vào thư viện
	}

	// TODO: Chuyển thư viện sang JSON và in ra
	fmt.Println(library.ToJSON())
}

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Go online