使用接口进行搜索
本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 101 课,共 107 课。
挑战
简单让我们为图书管理系统添加灵活的搜索功能!你将使用接口实现策略模式,让用户可以根据不同条件搜索图书,而无需修改核心库代码。
你将把代码组织到 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) bool实现 3 种搜索策略:
TitleSearch:如果图书标题中包含查询内容(不区分大小写),则匹配AuthorSearch:如果图书作者中包含查询内容(不区分大小写),则匹配ISBNSearch:如果图书的 ISBN 与查询内容完全一致,则匹配
library.go:定义包含图书和用户映射的Library结构体。添加一个Search方法,该方法接受任意SearchStrategy和一个查询字符串,并返回匹配图书指针组成的切片。该方法应遍历所有图书,并使用策略的Match方法查找结果。main.go:创建一个包含图书的图书馆,然后使用不同策略执行搜索。读取图书数量,然后逐本读取图书的 ID、标题、作者和 ISBN。接着读取搜索操作的数量。每个操作包含一种搜索类型(
title、author或isbn),后面跟着查询字符串。对于每次搜索,先输出
Search by [type]: [query],然后在下一行输出匹配图书的 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 在线编译器