Menu
Coddy logo textTech

Interfaceによる検索機能

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

challenge icon

チャレンジ

簡単

図書館管理システムに柔軟な検索機能を追加しましょう!インターフェースを使用してStrategyパターンを実装し、コアとなるライブラリのコードを修正することなく、ユーザーがさまざまな基準で本を検索できるようにします。

コードは以下の5つのファイルに分けて構成します:

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

    単一のメソッドを持つ 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 をカンマ区切りで出力します。一致する本がない場合は、代わりに 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 // ソリューションを実装する際にこの行を削除してください
	}
}

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