Назад к задачам
Junior — Senior
8

Декоратор с объединением одновременных запросов к клиенту

Получайте помощь с лайвкодингом в реальном времени с Sobes Copilot
Условие задачи

Необходимо создать обёртку‑декоратор над интерфейсом 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")
        // ...
    }()
}

Задача требует реализации синхронизации запросов, кэширования результата на время выполнения и корректного распределения ошибки/результата между всеми вызывающими.