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.
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: StructBookcủ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,authorvàavailable. Thêm hàm khởi tạoNewBook.user.go: StructUsercủa bạn với các thẻ JSON choid,name,emailvàborrowed_books. Thêm hàm khởi tạoNewUser.data.go: Tạo structLibraryDatalà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 (booksvàusers).library.go: StructLibrarycủ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ùngjson.MarshalIndentvớ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 structLibraryData, 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 structLibraryData, 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
1Nền tảng OOP trong Go
Tệp bên ngoàiWorkspace và module trong GoPackage và importTên được export và không được exportGiới thiệu về OOP trong GoStruct như lớpĐịnh nghĩa phương thức cho structReceiver kiểu con trỏ và kiểu giá trịKhởi tạo structHàm khởi tạoÔn tập: máy tính đơn giản4Interface
Giới thiệu về interfaceTriển khai ngầm địnhInterface như một hợp đồngInterface rỗng (any)Khẳng định kiểuswitch kiểuKết hợp interfaceInterface Stringer và ErrorÔn tập: Máy tính hình học7Tính đóng gói
Trường được xuất và không được xuấtĐóng gói ở cấp packagePhương thức getter và setterẨn thông tin trong GoÔn tập: hồ sơ học sinh10Generics (Go 1.18 trở lên)
Giới thiệu về GenericsTham số kiểuRàng buộc kiểuStruct tổng quátGiải pháp thay thế cho phương thức tổng quátÔn tập: tập hợp tổng quát13Các mẫu thiết kế phần 1
Giới thiệu về mẫu thiết kếMẫu SingletonMẫu FactoryMẫu Abstract FactoryMẫu ObserverMẫu Strategy2Tìm hiểu chuyên sâu về kiểu dữ liệu và struct
Kiểu cơ bản và kiểu tổng hợpĐịnh nghĩa kiểu dữ liệu tùy chỉnhThẻ structStruct ẩn danhStruct lồng nhauGiá trị zero và giá trị mặc địnhÔn tập: sổ liên lạc5Ưu tiên kết hợp hơn kế thừa
Vì sao Go không có kế thừaNhập môn nhúng structTự động nâng phương thứcNhúng nhiều structNhúng và kết tậpChe khuất phương thức được nhúngÔn tập: hệ phân cấp nhân viên8Xử lý lỗi và lập trình hướng đối tượng
Giao diện errorCác kiểu lỗi tùy chỉnhBọc lỗi với fmt.ErrorfLỗi sentinelerrors.Is() và errors.As()Panic, defer và recoverÔn tập: trình phân tích tệp3Con trỏ và bộ nhớ
Cơ bản về con trỏ trong GoCon trỏ đến structTruyền theo giá trị và tham chiếuHàm new()Thu gom rác trong GoÔn tập: xây dựng danh sách liên kết6Đa hình trong Go
Đa hình qua interfaceĐịnh kiểu vịt trong GoQuy tắc thỏa mãn interfaceCác tập hợp đa hìnhTiêm phụ thuộcÔn tập: bộ xử lý thanh toán9Lập trình đồng thời và lập trình hướng đối tượng
Cơ bản về goroutineChannel và giao tiếpChannel có bộ đệm và không có bộ đệmCâu lệnh selectsync.Mutex và sync.RWMutexsync.WaitGroupThiết kế struct an toàn luồngÔn tập: worker pool12Các khái niệm OOP nâng cao
Mẫu tùy chọn hàmMẫu Builder trong GoChuỗi phương thứcBí danh kiểu dữ liệu và định nghĩa kiểuCơ bản về reflectionTổng quan về tạo code15Dự án: Quản lý thư viện
Tổng quan và cấu trúc dự ánStruct về sách và người dùngTự luyện tập: Trình biên dịch Go online