Interfaceによる検索機能
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 101/107。
チャレンジ
簡単図書館管理システムに柔軟な検索機能を追加しましょう!インターフェースを使用してStrategyパターンを実装し、コアとなるライブラリのコードを修正することなく、ユーザーがさまざまな基準で本を検索できるようにします。
コードは以下の5つのファイルに分けて構成します:
book.go: 以前のレッスンで作成したBook構造体です。ID、Title、Author、ISBN、Availableフィールドを含めます。NewBookコンストラクタも含めてください。user.go:ID、Name、Email、BorrowedBooksフィールドを持つUser構造体です。NewUserコンストラクタも含めてください。search.go: 検索戦略のインターフェースとその実装を定義します。単一のメソッドを持つ
SearchStrategyインターフェースを作成します:Match(book *Book, query string) bool3つの検索戦略を実装します:
TitleSearch— 本のタイトルにクエリが含まれている場合に一致(大文字と小文字を区別しない)AuthorSearch— 本の著者にクエリが含まれている場合に一致(大文字と小文字を区別しない)ISBNSearch— 本のISBNがクエリと完全に一致する場合に一致
library.go: 本とユーザーを管理するマップを持つLibrary構造体です。任意のSearchStrategyとクエリ文字列を受け取り、一致する本のポインタのスライスを返すSearchメソッドを追加します。このメソッドはすべての本を反復処理し、戦略のMatchメソッドを使用して結果を見つける必要があります。main.go: 本を含むライブラリを構築し、異なる戦略を使用して検索を実行します。本の数を読み取り、次に各本について ID、タイトル、著者、ISBN を読み取ります。次に、検索操作の数を読み取ります。各操作は、検索タイプ(
title、author、または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,B002Search メソッドがいかに任意の戦略で動作するかに注目してください。タイトル、著者、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 // ソリューションを実装する際にこの行を削除してください
}
}
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー