go 事件机制(观察者设计模式)

背景:

公司目前有个业务,收到数据后,要分发给所有的客户端或者是业务模块,类似消息通知这样的需求,自然而然就想到了事件,观察者比较简单就自己实现以下,确保最小功能使用支持即可,其他的后期进行支持就行。

  • 创建事件结构体,用来发送事件信息
Go 复制代码
// Event
// @Description: 事件信息,作用:发生的动作或事情的描述
type Event struct {
	//默认false,进行同步处理;true异步处理
	AsyncHandle bool
	//事件名称
	EventName string
	//目标数据
	Data any
}
  • 创建事件监听者
Go 复制代码
// EventListener 定义监听器;事件监听器是一个函数,它接收事件并对其作出响应
type EventListener func(*Event)
  • 创建分发器,这快也可以不用这些,可以写到分发管理器里也是可以的,我这边主要是为了后期方便扩展使用的
Go 复制代码
// dispatcher
// @Description: 事件分发器
type dispatcher struct {
	//存储事件监听器,通过名称进行分组
	listeners map[string][]EventListener
}

// NewDispatcher
//
//	@Author  zhaosy
//	@Description: 新建分发器,不允许对外开放
//	@date  2024-08-07 17:12:36
func newDispatcher() *dispatcher {
	return &dispatcher{
		listeners: make(map[string][]EventListener),
	}
}
  • 创建分发管理以及相关业务
Go 复制代码
// 定义全局分发管理器
var eventDispatcherManagerObj = &eventDispatcherManager{
	dispatcher:      newDispatcher(),
	RegisterChannel: make(chan *eventListenerInfo),
	//容量给1000,后续可以根据情况进行设置大小即可
	EventChannel: make(chan *Event, 1000),
}

func init() {
	//异步进行启动
	go eventDispatcherManagerObj.Start()
}

// eventListenerInfo
// @Description: 监听者封装,供内部使用
type eventListenerInfo struct {
	EventName string
	EventListener
}

// eventDispatcherManager
// @Description: 事件分发处理器,供内部使用
type eventDispatcherManager struct {
	*dispatcher
	RegisterChannel chan *eventListenerInfo

	EventChannel chan *Event
}

// Start
//
//	@Author  zhaosy
//	@Description: 开始启动分发处理器
//	@date  2024-08-08 09:32:58
func (e *eventDispatcherManager) Start() {
	for {
		select {
		//发送事件
		case event := <-e.EventChannel:
			{
				//这里可以进行扩展,例如取消某个事件针对某个监听者分发

				fmt.Println("监听事件", event.EventName)
				//这里匹配是通过精确匹配,后期如果需要进行模糊匹配可以进行支持即可,例如前缀后缀这类的,进行扩展即可
				for _, listener := range e.listeners[event.EventName] {
					if event.AsyncHandle {
						//如果采用异步发布事件,事件顺序无法保证,也就是乱序,这里可以根据实际标志是否进行异步分发
						go listener(event) //通过协程进行处理
					} else {
						//默认采用同步方式进行分发事件
						listener(event)
					}

				}
			}
			//注册事件
		case register := <-e.RegisterChannel:
			{
				fmt.Println("注册事件", register.EventName)
				//进行注册
				e.dispatcher.listeners[register.EventName] = append(e.dispatcher.listeners[register.EventName], register.EventListener)
				fmt.Printf("注册事件结果:%#v", e.dispatcher.listeners)
			}
			//可以扩展取消事件
		}
	}

}
  • 监听者注册器,通过包名直接注册
Go 复制代码
// RegisterListener
//
//	@Author  zhaosy
//	@Description: 注册事件
//	@date  2024-08-08 09:05:10
func RegisterListener(eventName string, listener EventListener) error {
	if eventName == "" {
		return fmt.Errorf("event name is empty")
	}
	if listener == nil {
		return fmt.Errorf("listener is nil")
	}
	e := &eventListenerInfo{
		EventName:     eventName,
		EventListener: listener,
	}
	//发送到注册链
	eventDispatcherManagerObj.RegisterChannel <- e
	return nil
}
  • 发送监听
Go 复制代码
// Send
//
//	@Author  zhaosy
//	@Description: 发生事件
//	@date  2024-08-08 09:05:29
func Send(event *Event) error {
	if event == nil {
		return fmt.Errorf("event is nil")
	}
	if event.EventName == "" {
		return fmt.Errorf("event name is empty")
	}

	eventDispatcherManagerObj.EventChannel <- event
	return nil
}

测试:

Go 复制代码
func TestEvent(t *testing.T) {
	eventName := "test"
	events.RegisterListener(eventName, func(event *events.Event) {
		//这里建议使用goroutine进行异步处理业务,这样不会拖慢事件分发器分发效率
		// go dosomething(event)
		fmt.Println("第一个监听器", event.EventName, event.Data)
	})

	events.RegisterListener(eventName, func(event *events.Event) {
		fmt.Println("第二个监听器", event.EventName, event.Data)
	})

    //模拟发送事件消息
	for i := 0; i < 10; i++ {
		//走同步
		if i < 6 {
			events.Send(&events.Event{
				EventName: eventName,
				Data:      i,
			})
		} else {
           //走异步
			events.Send(&events.Event{
				AsyncHandle: true,
				EventName:   eventName,
				Data:        i,
			})
		}

	}

	time.Sleep(5 * time.Second)
}

结果:

相关推荐
晨米酱7 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
数据智能老司机12 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机13 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机13 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机13 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
使一颗心免于哀伤13 小时前
《设计模式之禅》笔记摘录 - 21.状态模式
笔记·设计模式
数据智能老司机1 天前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
烛阴2 天前
【TS 设计模式完全指南】懒加载、缓存与权限控制:代理模式在 TypeScript 中的三大妙用
javascript·设计模式·typescript
李广坤2 天前
工厂模式
设计模式