Menu
Coddy logo textTech

管理者用CLIインターフェース

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

challenge icon

チャレンジ

簡単

Command Patternを使って、Library Management Systemのコマンドラインインターフェースを構築しましょう! 本演習では、書籍の追加、ユーザーの登録、貸出操作の管理といった管理者コマンドを処理するCLIを、すっきりと拡張しやすいアーキテクチャで作成します。

コードは6つのファイルに分けて整理します。

  • book.go: IDTitleAuthorISBNAvailableのJSONタグを持つBook構造体です。NewBookコンストラクターも含めます。
  • user.go: IDNameEmailBorrowedBooksのJSONタグを持つUser構造体です。NewUserコンストラクターも含めます。
  • library.go: 書籍とユーザーのマップを持つLibrary構造体です。前のレッスンで実装したAddBookAddUserBorrowReturnメソッドも含めます。
  • commands.go: ここでCommand Patternを実際に実装します! *Library[]stringのargsを受け取り、文字列の結果を返すExecuteメソッドを持つCommandインターフェースを定義します。次に、以下のコマンド構造体を実装します。
    • AddBookCommand: 4つのargs(id、title、author、isbn)を受け取ります。書籍を追加し、Book added: [title]を返します。
    • AddUserCommand: 3つのargs(id、name、email)を受け取ります。ユーザーを追加し、User added: [name]を返します。
    • BorrowCommand: 2つのargs(userID、bookID)を受け取ります。成功時はBorrowed: [bookID]を、失敗時はError: [message]を返します。
    • ReturnCommand: 2つのargs(userID、bookID)を受け取ります。成功時はReturned: [bookID]を、失敗時はError: [message]を返します。
    • ListBooksCommand: argsは受け取りません。各書籍のIDとタイトルを、[id]: [title]形式で1行ずつ返します。空の場合はNo booksを返します(書籍はID順に並べます)。

    コマンドに必要な数の引数が渡されなかった場合は、Error: insufficient argumentsを返します。

  • cli.go: Libraryへのポインターと、コマンド名からCommand実装へのマップを保持するCLI構造体を作成します。以下を実装します。
    • ライブラリでCLIを初期化し、すべてのコマンド(addbookadduserborrowreturnlistbooks)を登録するNewCLIコンストラクター
    • 入力文字列を受け取り、strings.Fieldsを使って解析し、コマンドを検索して実行するRunメソッド。入力が空の場合はNo command providedを、認識できないコマンドの場合はUnknown command: [name]を返します。
  • main.go: ライブラリとCLIを作成し、入力からコマンドを処理します。コマンド数を読み取った後、各コマンド文字列を別々の行から読み取ります。各コマンドについてRunを呼び出し、結果を出力します。

次の入力が与えられます。

  • コマンド数
  • それぞれ独立した行に記述された完全なコマンド

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

6
addbook B001 Go-Programming Alan-Donovan 978-0134190440
addbook B002 Clean-Code Robert-Martin 978-0132350884
adduser U001 Alice alice@test.com
borrow U001 B001
listbooks
borrow U001 B001

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

Book added: Go-Programming
Book added: Clean-Code
User added: Alice
Borrowed: B001
B001: Go-Programming
B002: Clean-Code
Error: book not available

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

4
listbooks
addbook B100 Design-Patterns Gang-of-Four 978-0201633610
listbooks
invalidcmd test

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

No books
Book added: Design-Patterns
B100: Design-Patterns
Unknown command: invalidcmd

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

5
adduser U001 Bob bob@email.com
borrow U001 B001
addbook B001 Golang-Guide John-Smith 123-456
borrow U001 B001
return U001 B001

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

User added: Bob
Error: book not found
Book added: Golang-Guide
Borrowed: B001
Returned: B001

CLIは各操作の詳細を知る必要がないことに注目してください。CLIはコマンドを検索し、実行を委譲するだけです。そのため、新しいコマンドの追加は、Commandインターフェースを実装する新しい構造体を作成し、それをCLIに登録するだけで簡単に行えます。

自分で試してみよう

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	// コマンドの数を読み取る
	var n int
	fmt.Scanln(&n)

	// 行全体を読み取るスキャナーを作成する
	scanner := bufio.NewScanner(os.Stdin)

	// TODO: 新しい Library を作成する

	// TODO: ライブラリを使って新しい CLI を作成する

	// TODO: 各コマンドを処理する
	// n 個の各コマンドについて:
	// - scanner.Scan() と scanner.Text() を使ってコマンド行を読み取る
	// - CLI を通じてコマンドを実行する
	// - 結果を出力する

	_ = scanner // scanner を使用したらこの行を削除する
}

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

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