Назад к вопросам
Купер
Middle+
3
Реализовать метод grpc-сервера AddItemAndOrder: 1. Добавить товары в корзину 2. Обязательно сообщить возможным потребителям о факте оформления корзины через брокер сообщений. 3. При изменении состава корзины надо пересчитывать basket.Total=sum(count*price) 4. Все элементы корзины должны быть уникальны по ключу ProductID 5. Для оформления корзины необходимо сменить ее статус на ordered 6. В оформленные корзины изменения вносить нельзя
Компании, где спрашивали
Ответ от нейросети
sobes.tech AI
Ниже пример реализации метода AddItemAndOrder для gRPC-сервера на Go с учетом требований:
- Корзина (
Basket) содержит уникальные товары поProductID. - При добавлении товаров пересчитывается сумма
Total. - При оформлении корзины меняется статус на
ordered. - После оформления изменения запрещены.
- После оформления отправляется сообщение через брокер (например, через интерфейс
MessageBroker).
package service
import (
"context"
"errors"
"sync"
)
// Пример структур
type BasketStatus string
const (
StatusOpen BasketStatus = "open"
StatusOrdered BasketStatus = "ordered"
)
type BasketItem struct {
ProductID string
Count int
Price float64
}
type Basket struct {
ID string
Items map[string]*BasketItem // ключ - ProductID
Total float64
Status BasketStatus
mu sync.Mutex
}
// Интерфейс брокера сообщений
type MessageBroker interface {
Publish(topic string, message interface{}) error
}
// Сервис с корзинами и брокером
type BasketService struct {
baskets map[string]*Basket
broker MessageBroker
}
func NewBasketService(broker MessageBroker) *BasketService {
return &BasketService{
baskets: make(map[string]*Basket),
broker: broker,
}
}
// AddItemAndOrderRequest и Response - protobuf-сгенерированные структуры
func (s *BasketService) AddItemAndOrder(ctx context.Context, req *AddItemAndOrderRequest) (*AddItemAndOrderResponse, error) {
basket, ok := s.baskets[req.BasketId]
if !ok {
return nil, errors.New("basket not found")
}
basket.mu.Lock()
defer basket.mu.Unlock()
if basket.Status == StatusOrdered {
return nil, errors.New("cannot modify ordered basket")
}
// Добавляем или обновляем товары
for _, item := range req.Items {
if existing, exists := basket.Items[item.ProductId]; exists {
existing.Count += int(item.Count)
existing.Price = item.Price // обновляем цену, если нужно
} else {
basket.Items[item.ProductId] = &BasketItem{
ProductID: item.ProductId,
Count: int(item.Count),
Price: item.Price,
}
}
}
// Пересчет суммы
var total float64
for _, item := range basket.Items {
total += float64(item.Count) * item.Price
}
basket.Total = total
// Если в запросе есть флаг оформления корзины
if req.Order { // предположим, что есть булево поле Order
basket.Status = StatusOrdered
// Отправляем сообщение в брокер
err := s.broker.Publish("basket_ordered", map[string]interface{}{
"basket_id": basket.ID,
"total": basket.Total,
"items": basket.Items,
})
if err != nil {
return nil, err
}
}
return &AddItemAndOrderResponse{
Total: basket.Total,
Status: string(basket.Status),
}, nil
}
В этом примере:
- Используется мьютекс для защиты данных корзины от гонок.
- Товары хранятся в мапе для уникальности по
ProductID. - При оформлении меняется статус и отправляется событие через брокер.
- После оформления любые изменения запрещены.
Для реального приложения нужно добавить валидацию, обработку ошибок и интеграцию с реальным брокером сообщений.