golang实现观察者模式的事件管理插件库event的使用
golang实现观察者模式的事件管理插件库event的使用
快速示例
import (
"github.com/agoalofalife/event"
)
func main() {
// 创建事件管理器
e := event.New()
// 添加订阅者
e.Add("push.email", func(text string){
// 业务逻辑
}, "text")
// 触发事件
e.Fire("push.email") // 或者使用 e.Go("push.email")
}
让我们分析这个示例:
- 首先需要创建事件管理器结构体
- 然后添加订阅者:
- 第一个参数是事件名称(string类型)
- 第二个参数是事件触发时执行的函数
- 第三个参数是传递给函数的参数列表
- 最后触发事件,可以使用
Fire
方法或其别名Go
订阅者方法示例
type Email struct {
count int
}
// 定义事件处理方法
func (e *Email) Push() {
e.count += 1
fmt.Printf("Push email again, count %d \n", e.count)
}
func main() {
e := event.New()
email := new(Email)
// 添加结构体方法作为事件处理
e.Add(email, email.Push)
// 触发事件
e.Fire(email)
e.Fire(email)
}
// 输出:
// Push email again, count 1
// Push email again, count 2
在这个示例中,我们注册了一个结构体方法作为事件处理器。
性能基准测试
// 创建结构体并添加新事件处理程序
BenchmarkAdd-8 1000000 1482 ns/op
// 创建结构体并添加新事件处理程序并多次运行该处理程序
BenchmarkGo-8 5000000 339 ns/op
完整示例demo
package main
import (
"fmt"
"github.com/agoalofalife/event"
)
// 定义用户结构体
type User struct {
Name string
}
// 用户登录事件处理
func (u *User) OnLogin() {
fmt.Printf("User %s logged in\n", u.Name)
}
func main() {
// 创建事件管理器
em := event.New()
// 示例1: 使用匿名函数作为事件处理
em.Add("user.register", func(name, email string) {
fmt.Printf("New user registered: %s (%s)\n", name, email)
}, "John Doe", "john@example.com")
// 示例2: 使用结构体方法作为事件处理
user := &User{Name: "Alice"}
em.Add("user.login", user.OnLogin)
// 触发事件
fmt.Println("Triggering events:")
em.Fire("user.register")
em.Fire("user.login")
// 示例3: 带参数的事件
em.Add("order.created", func(orderID int, amount float64) {
fmt.Printf("Order created - ID: %d, Amount: $%.2f\n", orderID, amount)
}, 12345, 99.99)
em.Fire("order.created")
}
这个完整的示例展示了:
- 使用匿名函数作为事件处理器
- 使用结构体方法作为事件处理器
- 传递不同类型参数的事件处理
- 多种事件类型的触发
更多关于golang实现观察者模式的事件管理插件库event的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现观察者模式的事件管理插件库event的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 实现观察者模式的事件管理库
观察者模式是一种常用的设计模式,它定义了对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会得到通知并自动更新。下面我将介绍如何使用Golang实现一个简单但功能完备的事件管理库。
基本实现
package event
import (
"sync"
)
// EventHandler 事件处理函数类型
type EventHandler func(interface{})
// Event 事件结构体
type Event struct {
handlers []EventHandler
mu sync.RWMutex
}
// NewEvent 创建新事件
func NewEvent() *Event {
return &Event{
handlers: make([]EventHandler, 0),
}
}
// Subscribe 订阅事件
func (e *Event) Subscribe(handler EventHandler) {
e.mu.Lock()
defer e.mu.Unlock()
e.handlers = append(e.handlers, handler)
}
// Unsubscribe 取消订阅
func (e *Event) Unsubscribe(handler EventHandler) {
e.mu.Lock()
defer e.mu.Unlock()
for i, h := range e.handlers {
if &h == &handler {
e.handlers = append(e.handlers[:i], e.handlers[i+1:]...)
break
}
}
}
// Emit 触发事件
func (e *Event) Emit(data interface{}) {
e.mu.RLock()
defer e.mu.RUnlock()
for _, handler := range e.handlers {
go handler(data) // 使用goroutine异步处理
}
}
使用示例
package main
import (
"fmt"
"time"
"./event" // 替换为你的event包路径
)
func main() {
// 创建事件
loginEvent := event.NewEvent()
// 订阅者1
subscriber1 := func(data interface{}) {
user, ok := data.(string)
if !ok {
return
}
fmt.Printf("Subscriber1: 用户 %s 登录了\n", user)
}
// 订阅者2
subscriber2 := func(data interface{}) {
user, ok := data.(string)
if !ok {
return
}
fmt.Printf("Subscriber2: 检测到 %s 登录\n", user)
}
// 订阅事件
loginEvent.Subscribe(subscriber1)
loginEvent.Subscribe(subscriber2)
// 模拟用户登录
fmt.Println("用户admin登录中...")
loginEvent.Emit("admin")
// 等待goroutine执行
time.Sleep(100 * time.Millisecond)
// 取消订阅
loginEvent.Unsubscribe(subscriber1)
// 再次触发事件
fmt.Println("\n用户guest登录中...")
loginEvent.Emit("guest")
time.Sleep(100 * time.Millisecond)
}
高级功能扩展
1. 带优先级的事件处理
type PriorityHandler struct {
Handler EventHandler
Priority int // 优先级,数字越小优先级越高
}
type Event struct {
handlers []PriorityHandler
mu sync.RWMutex
}
func (e *Event) SubscribeWithPriority(handler EventHandler, priority int) {
e.mu.Lock()
defer e.mu.Unlock()
ph := PriorityHandler{
Handler: handler,
Priority: priority,
}
// 按优先级插入
for i, h := range e.handlers {
if priority < h.Priority {
e.handlers = append(e.handlers[:i], append([]PriorityHandler{ph}, e.handlers[i:]...)...)
return
}
}
e.handlers = append(e.handlers, ph)
}
2. 同步/异步触发控制
func (e *Event) EmitSync(data interface{}) {
e.mu.RLock()
defer e.mu.RUnlock()
for _, handler := range e.handlers {
handler(data) // 同步处理
}
}
func (e *Event) EmitAsync(data interface{}) {
e.mu.RLock()
handlers := make([]EventHandler, len(e.handlers))
copy(handlers, e.handlers)
e.mu.RUnlock()
for _, handler := range handlers {
go handler(data) // 异步处理
}
}
3. 事件总线实现
type EventBus struct {
events map[string]*Event
mu sync.RWMutex
}
func NewEventBus() *EventBus {
return &EventBus{
events: make(map[string]*Event),
}
}
func (eb *EventBus) Subscribe(eventName string, handler EventHandler) {
eb.mu.Lock()
defer eb.mu.Unlock()
if _, ok := eb.events[eventName]; !ok {
eb.events[eventName] = NewEvent()
}
eb.events[eventName].Subscribe(handler)
}
func (eb *EventBus) Emit(eventName string, data interface{}) {
eb.mu.RLock()
defer eb.mu.RUnlock()
if event, ok := eb.events[eventName]; ok {
event.Emit(data)
}
}
使用建议
- 命名规范:事件名称应使用清晰、明确的命名,如
UserLoggedIn
、OrderCreated
等 - 错误处理:在事件处理函数中添加recover机制防止单个处理函数崩溃影响整体
- 性能考虑:对于高频事件,考虑使用对象池减少GC压力
- 测试:确保编写单元测试覆盖各种场景
这个事件管理库提供了观察者模式的基本实现,可以根据项目需求进一步扩展功能。它解耦了事件发布者和订阅者,使系统更加灵活和可维护。