Menu
Coddy logo textTech

JSON永続化レイヤー

CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 102/107。

challenge icon

チャレンジ

簡単

Library Management System にデータ永続化を追加しましょう!JSON 永続化レイヤーを実装して、保存するために library のデータを JSON 形式に変換し、JSON 文字列から再び読み込めるようにします。これは、セッション間でデータを保持する必要がある実際のアプリケーションに不可欠です。

コードを5つのファイルに整理します。

  • book.go: シリアル化を制御する JSON 構造体タグを持つ Book 構造体です。各フィールドには対応する JSON タグ、idtitleauthorisbnavailable を設定します。NewBook コンストラクターも含めてください。
  • user.go: idnameemailborrowed_books の JSON 構造体タグを持つ User 構造体です。NewUser コンストラクターも含めてください。
  • data.go: JSON シリアル化のための転送オブジェクトとして機能する LibraryData 構造体を作成します。2つのフィールド、Book ポインターのスライスである Books と User ポインターのスライスである Users を持たせ、それぞれに適切な JSON タグ(booksusers)を設定します。
  • library.go: books と users のマップを持つ Library 構造体です。2つの新しいメソッドを追加します。
    • ToJSON(): json.MarshalIndent を使用し、2スペースのインデントで library のデータを整形済み JSON 文字列に変換します。マップからすべての books と users を収集して LibraryData 構造体に格納し、その後シリアル化します。
    • FromJSON(jsonStr string): JSON 文字列を受け取り、それを LibraryData 構造体にアンマーシャルして、読み込んだ books と users を library のマップに格納します。
  • main.go: library を構築して JSON に変換することで、永続化レイヤーを実演します。

    books の数を読み取り、次に各 book について ID、title、author、ISBN を読み取ります。続いて users の数を読み取り、各 user について ID、name、email を読み取ります。library にデータを追加したら、ToJSON() を呼び出して、結果の JSON 文字列を出力します。

次の入力が提供されます。

  • books の数、その後に各 book の ID、title、author、ISBN(それぞれ別の行)
  • users の数、その後に各 user の ID、name、email(それぞれ別の行)

例えば、次の入力が与えられた場合:

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

出力は次のようになります。

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

また、次の入力が与えられた場合:

1
B100
Design Patterns
Gang of Four
978-0201633610
0

出力は次のようになります。

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

重要:スライスを構築するためにマップを反復処理する際は、books を B001、B002 などの順番(ID のアルファベット順)で追加し、users についても同様にしてください。これにより、一貫した JSON 出力が保証されます。反復処理の前に、マップのキーに対して sort.Strings を使用できます。

LibraryData 構造体は、マップベースのストレージと JSON の配列ベースの形式の間を橋渡しします。この転送オブジェクトパターンは、複雑なデータ構造をシリアル化する際によく使われます。

自分で試してみよう

package main

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

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

	// 新しいライブラリを作成する
	library := NewLibrary()

	// 本の数を読み取る
	numBooksStr, _ := reader.ReadString('\n')
	numBooks, _ := strconv.Atoi(strings.TrimSpace(numBooksStr))

	// TODO: 各本の詳細(ID、title、author、ISBN)を読み取る
	// そしてそれらをライブラリに追加する
	for i := 0; i < numBooks; i++ {
		// TODO: 本のIDを読み取る
		// TODO: 本のtitleを読み取る
		// TODO: 本のauthorを読み取る
		// TODO: 本のISBNを読み取る
		// TODO: 本を作成してライブラリに追加する
	}

	// ユーザーの数を読み取る
	numUsersStr, _ := reader.ReadString('\n')
	numUsers, _ := strconv.Atoi(strings.TrimSpace(numUsersStr))

	// TODO: 各ユーザーの詳細(ID、name、email)を読み取る
	// そしてそれらをライブラリに追加する
	for i := 0; i < numUsers; i++ {
		// TODO: ユーザーのIDを読み取る
		// TODO: ユーザー名を読み取る
		// TODO: ユーザーのメールを読み取る
		// TODO: ユーザーを作成して library に追加する
	}

	// TODO: library を JSON に変換して出力する
	fmt.Println(library.ToJSON())
}

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Goオンラインコンパイラ