Ответ
В Go нет встроенной поддержки триггеров как в SQL, но их можно эмулировать с помощью методов-наблюдателей или паттерна "Наблюдатель" (Observer), который позволяет объектам уведомлять другие объекты об изменениях своего состояния.
Пример (базовая реализация паттерна Observer):
package main
import "fmt"
// Trigger определяет тип функции-наблюдателя, которая будет вызываться при изменении.
// Она принимает старое и новое значение.
type Trigger func(old, new interface{})
// Observable представляет объект, за которым можно наблюдать.
type Observable struct {
value interface{}
triggers []Trigger
}
// Set устанавливает новое значение и уведомляет всех наблюдателей.
func (o *Observable) Set(value interface{}) {
old := o.value
o.value = value
// Вызываем все зарегистрированные триггеры
for _, trigger := range o.triggers {
trigger(old, value)
}
}
// AddTrigger добавляет новую функцию-наблюдатель к списку.
func (o *Observable) AddTrigger(t Trigger) {
o.triggers = append(o.triggers, t)
}
func main() {
obj := Observable{}
// Добавляем первый наблюдатель
obj.AddTrigger(func(old, new interface{}) {
fmt.Printf("Наблюдатель 1: Значение изменилось с %v на %vn", old, new)
})
// Добавляем второй наблюдатель
obj.AddTrigger(func(old, new interface{}) {
fmt.Printf("Наблюдатель 2: Обновление! Новое значение: %vn", new)
})
fmt.Println("Устанавливаем значение 42...")
obj.Set(42) // Вызовет оба триггера
fmt.Println("nУстанавливаем значение 'hello'...")
obj.Set("hello") // Вызовет оба триггера
fmt.Println("nУстанавливаем значение 123.45...")
obj.Set(123.45) // Вызовет оба триггера
}
Пояснения и улучшения:
- Эта базовая реализация использует
interface{}
, что позволяет передавать любые типы данных. Однако это требует ручной проверки типов (с помощью утверждений типаvalue.(int)
) при их использовании внутри функцийTrigger
. - В Go 1.18+ для более типобезопасных решений можно использовать дженерики (generics), чтобы определить
Observable
иTrigger
для конкретного типа данных, избегая необходимости вinterface{}
и утверждениях типа. - Для более сложных сценариев, таких как асинхронная обработка событий, отписка от событий, или когда требуется более сложная маршрутизация событий, можно использовать:
- Event Bus: Специализированные библиотеки, такие как
github.com/asaskevich/EventBus
, предоставляют более мощные механизмы для публикации и подписки на события. - Системы очередей сообщений: Для распределенных систем или когда требуется надежная доставка и персистентность событий, используются внешние брокеры сообщений, такие как Kafka, RabbitMQ или NATS.
- Event Bus: Специализированные библиотеки, такие как