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")
}

让我们分析这个示例:

  1. 首先需要创建事件管理器结构体
  2. 然后添加订阅者:
    • 第一个参数是事件名称(string类型)
    • 第二个参数是事件触发时执行的函数
    • 第三个参数是传递给函数的参数列表
  3. 最后触发事件,可以使用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")
}

这个完整的示例展示了:

  1. 使用匿名函数作为事件处理器
  2. 使用结构体方法作为事件处理器
  3. 传递不同类型参数的事件处理
  4. 多种事件类型的触发

更多关于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)
	}
}

使用建议

  1. 命名规范:事件名称应使用清晰、明确的命名,如UserLoggedInOrderCreated
  2. 错误处理:在事件处理函数中添加recover机制防止单个处理函数崩溃影响整体
  3. 性能考虑:对于高频事件,考虑使用对象池减少GC压力
  4. 测试:确保编写单元测试覆盖各种场景

这个事件管理库提供了观察者模式的基本实现,可以根据项目需求进一步扩展功能。它解耦了事件发布者和订阅者,使系统更加灵活和可维护。

回到顶部