Назад к задачамПолучайте помощь с лайвкодингом в реальном времени с Sobes Copilot
Junior — Senior
8
Декоратор с объединением одновременных запросов к клиенту
Условие задачи
Необходимо создать обёртку‑декоратор над интерфейсом Client, которая будет гарантировать, что при одновременных вызовах метода GetUser(name):
- если переданные имена совпадают (например, "Vasya"), реальная реализация Client.GetUser("Vasya") будет выполнена только один раз;
- если имена различаются ("Vasya" и "Oleg"), запросы обрабатываются независимо.
Метод Client.GetUser является ресурсоёмким и дорогим, поэтому важно, чтобы запросы с одинаковым параметром выполнялись единожды, а полученный результат распределялся между всеми горутинами, сделавшими запрос.
type User struct {
Id int64
}
type IClient interface {
GetUser(name string) (*User, error)
}
type Client struct {}
func (c Client) GetUser(name string) (*User, error) {
// дорогостоящая операция
return &User{}, nil
}
func NewClient() *Client {
return &Client{}
}
type Decorator struct {
client IClient
// ...
}
func (d *Decorator) GetUser(name string) (*User, error) {
// ...
}
func NewDecorator(c IClient) *Decorator {
return &Decorator{client: c}
}
Пример использования:
func main() {
client := NewClient()
changedClient := NewDecorator(client)
go func() {
vasya, err := changedClient.GetUser("Vasya")
// ...
}()
go func() {
vasya, err := changedClient.GetUser("Vasya")
// ...
}()
go func() {
vasya, err := changedClient.GetUser("Vasya")
// ...
}()
go func() {
vasya, err := changedClient.GetUser("Vasya")
// ...
}()
go func() {
oleg, err := changedClient.GetUser("Oleg")
// ...
}()
go func() {
oleg, err := changedClient.GetUser("Oleg")
// ...
}()
}
Задача требует реализации синхронизации запросов, кэширования результата на время выполнения и корректного распределения ошибки/результата между всеми вызывающими.