Menu
Coddy logo textTech

Interfaceによる検索機能

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

challenge icon

チャレンジ

簡単

Library Management System に柔軟な検索機能を追加しましょう!インターフェースを使って Strategy パターンを実装し、ライブラリのコアコードを変更せずに、さまざまな条件で本を検索できるようにします。

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

  • book.go: 前のレッスンで作成した、IDTitleAuthorISBNAvailable フィールドを持つ Book 構造体です。NewBook コンストラクターも含めます。
  • user.go: IDNameEmailBorrowedBooks フィールドを持つ User 構造体です。NewUser コンストラクターも含めます。
  • search.go: 検索戦略のインターフェースと実装を定義します。

    次の1つのメソッドを持つ SearchStrategy インターフェースを作成します。

    Match(book *Book, query string) bool

    3つの検索戦略を実装します。

    • TitleSearch: 本のタイトルにクエリが含まれている場合に一致します(大文字と小文字を区別しません)
    • AuthorSearch: 本の著者名にクエリが含まれている場合に一致します(大文字と小文字を区別しません)
    • ISBNSearch: 本の ISBN がクエリと完全に等しい場合に一致します
  • library.go: 本とユーザーのマップを持つ Library 構造体です。任意の SearchStrategy とクエリ文字列を受け取り、一致する本のポインターのスライスを返す Search メソッドを追加します。このメソッドでは、すべての本を反復処理し、戦略の Match メソッドを使って結果を見つけます。
  • main.go: 本を登録したライブラリを作成し、さまざまな戦略を使って検索を実行します。

    まず本の数を読み取り、次に各本について ID、タイトル、著者、ISBN を読み取ります。続いて、検索操作の数を読み取ります。各操作は、検索タイプ(titleauthor、または isbn)と、それに続くクエリ文字列で構成されます。

    各検索では、Search by [type]: [query] を出力し、次の行に一致する本の ID を昇順で出力します。ID はカンマで区切ります(マップはランダムな順序で反復されるため、出力前に ID をソートします)。一致する本がない場合は、代わりに No results を出力します。

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

  • 本の数、その後に各本の ID、タイトル、著者、ISBN(それぞれ別の行)
  • 検索数、その後に各検索タイプとクエリ(それぞれ別の行)

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

3
B001
The Go Programming Language
Alan Donovan
978-0134190440
B002
Go in Action
William Kennedy
978-1617291784
B003
Learning Python
Mark Lutz
978-1449355739
3
title
go
author
kennedy
isbn
978-1449355739

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

Search by title: go
B001,B002
Search by author: kennedy
B002
Search by isbn: 978-1449355739
B003

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

2
B001
Clean Code
Robert Martin
978-0132350884
B002
The Pragmatic Programmer
David Thomas
978-0135957059
2
title
java
author
martin

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

Search by title: java
No results
Search by author: martin
B001

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

2
B001
Design Patterns
Gang of Four
978-0201633610
B002
Head First Design Patterns
Eric Freeman
978-0596007126
1
title
design

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

Search by title: design
B001,B002

Search メソッドがどの戦略でも動作することに注目してください。このメソッドは、タイトル、著者、ISBN のどれで検索しているのかを知る必要がありません。このポリモーフィックなアプローチにより、SearchStrategy を実装する新しい構造体を作成するだけで、空き状況や出版年など、新しい検索タイプを簡単に追加できます。

自分で試してみよう

package main

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

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

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

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

	// 各本の詳細を読み取る
	for i := 0; i < numBooks; i++ {
		id, _ := reader.ReadString('\n')
		id = strings.TrimSpace(id)
		title, _ := reader.ReadString('\n')
		title = strings.TrimSpace(title)
		author, _ := reader.ReadString('\n')
		author = strings.TrimSpace(author)
		isbn, _ := reader.ReadString('\n')
		isbn = strings.TrimSpace(isbn)

		book := NewBook(id, title, author, isbn)
		library.AddBook(book)
	}

	// 検索の数を読み取る
	numSearchesStr, _ := reader.ReadString('\n')
	numSearches, _ := strconv.Atoi(strings.TrimSpace(numSearchesStr))

	// 各検索を処理する
	for i := 0; i < numSearches; i++ {
		searchType, _ := reader.ReadString('\n')
		searchType = strings.TrimSpace(searchType)
		query, _ := reader.ReadString('\n')
		query = strings.TrimSpace(query)

		// TODO: searchType に基づいて適切な検索戦略を選択する
		// searchType は "title"、"author"、または "isbn" のいずれか
		var strategy SearchStrategy

		// TODO: ここで戦略選択ロジックを実装する

		// TODO: library.Search(strategy, query) を使用して検索を実行する

		// TODO: 結果を指定の形式で出力する
		// 形式: "Search by [type]: [query]" に続いて一致する ID、または "No results"
		fmt.Printf("Search by %s: %s\n", searchType, query)

		// TODO: 一致する本の ID をカンマ区切りで出力するか、"No results" を出力する
		_ = strategy // ソリューションを実装したらこの行を削除してください
	}
}

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

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