Поиск через Interfaces
Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy. Урок 101 из 107.
Задание
ЛегкоДобавим гибкие возможности поиска в нашу систему управления библиотекой! Вы реализуете паттерн «Стратегия» с использованием интерфейсов, что позволит пользователям искать книги по разным критериям без изменения основного кода библиотеки.
Вы организуете код в пяти файлах:
book.go: ваша структураBookиз предыдущих уроков с полямиID,Title,Author,ISBNиAvailable. Включите конструкторNewBook.user.go: ваша структураUserс полямиID,Name,EmailиBorrowedBooks. Включите конструкторNewUser.search.go: определите интерфейс стратегии поиска и его реализации.Создайте интерфейс
SearchStrategyс единственным методом:Match(book *Book, query string) boolРеализуйте три стратегии поиска:
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 // Удалите эту строку, когда реализуете решение
}
}
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП в Go
Внешние файлыРабочее пространство и модули GoПакеты и импортыЭкспортируемые и неэкспортируемые именаВведение в ООП в GoСтруктуры как классыОпределение методов структурПолучатели-указатели и получатели-значенияИнициализация структурФункции-конструкторыИтоги — Простой калькулятор4Интерфейсы
Введение в интерфейсыНеявная реализацияИнтерфейс как контрактПустой интерфейс (any)Утверждение типаПереключатель типовКомпозиция интерфейсовИнтерфейсы Stringer и ErrorПовторение: Калькулятор фигур7Инкапсуляция
Экспортируемые и неэкспортируемые поляИнкапсуляция на уровне пакетовГеттеры и сеттерыСокрытие информации в GoИтоги — Записи о студентах10Обобщения (Generics) (Go 1.18+)
Введение в GenericsПараметры типовОграничения типовОбобщенные структурыОбходной путь для обобщенных методовИтоги — Обобщенная коллекция13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн Abstract FactoryПаттерн ObserverПаттерн Strategy2Глубокое погружение в типы и структуры
Базовые и составные типыОпределение пользовательских типовТеги структурАнонимные структурыВложенные структурыНулевые значения и значения по умолчаниюПовторение — Контактная книга5Композиция вместо наследования
Почему в Go нет наследованияОсновы встраивания структурПродвижение методовВстраивание нескольких структурВстраивание против агрегацииЗатенение встроенных методовИтоги — Иерархия сотрудников8Обработка ошибок и ООП
Интерфейс errorПользовательские типы ошибокОбертывание ошибок (fmt.Errorf)Sentinel-ошибкиerrors.Is() и errors.As()Panic, Defer и RecoverИтоги — Парсер файлов11Стандартная библиотека и ООП
io.Reader и io.Writersort.InterfaceИнтерфейс fmt.Stringerencoding/json со структурамиИнтерфейс http.HandlerПовторение: модели REST API14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикMiddleware как Декоратор3Указатели и память
Основы указателей в GoУказатели на структурыПередача по значению и по ссылкеФункция new()Сборка мусора в GoПовторение: Конструктор связного списка6Полиморфизм в Go
Полиморфизм через интерфейсыУтиная типизация в GoПравила реализации интерфейсовПолиморфные коллекцииВнедрение зависимостейИтоги — Обработчик платежей9Конкурентность и ООП
Основы горутинКаналы и взаимодействиеБуферизованные и небуферизованные каналыОператор selectsync.Mutex и sync.RWMutexsync.WaitGroupПроектирование потокобезопасных структурПовторение — Worker Pool12Продвинутые концепции ООП
Паттерн функциональных опцийПаттерн Builder в GoЦепочки вызовов методовПсевдонимы и определения типовОсновы рефлексииОбзор генерации кода15Проект: Управление библиотекой
Обзор и структура проектаСтруктуры Book и UserПотренируйтесь самостоятельно: Онлайн-компилятор Go