Menu
CoddyTech

使用接口进行搜索

本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 101 课,共 107 课。

challenge icon

挑战

简单

让我们为图书管理系统添加灵活的搜索功能!你将使用接口实现策略模式,让用户可以根据不同条件搜索图书,而无需修改核心库代码。

你将把代码组织到 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 在线编译器