關注公眾號【愛發白日夢的后端】分享技術干貨、讀書筆記、開源項目、實戰經驗、高效開發工具等,您的關注將是我的更新動力!
在編程中,事件管理器是一種常見的工具,用于通過通知來觸發操作。在Go語言中,我們可以通過創建事件管理器和監聽器來實現事件的處理。本文將介紹一個簡單的Go事件管理器的實現,并通過異步改進提高其性能。
監聽器
首先,我們需要創建一個監聽器。在這個實現中,監聽器只是一個接收事件參數的函數。
type Listener[T any] func(T)
事件管理器
事件管理器是一個用于管理事件和監聽器的結構。它具有兩個方法:Add
和Run
。Add
方法用于將新的監聽器附加到事件上,而Run
方法用于執行事件管理器。
type Manager[T any] interface {Add(n string, l Listener[T])Run()
}
抽象事件管理器
為了方便使用,我們可以創建一個抽象事件管理器,它實現了事件管理器接口的一部分通用邏輯。雖然Go語言并不是面向對象的,但我們可以通過模擬來實現類似的效果。
type BaseManager[T any] struct {lst map[string][]Listener[T]
}func (m *BaseManager[T]) Invoke(n string, args T) {for _, ls := range m.lst[n] {ls(args)}
}func (m *BaseManager[T]) Add(n string, l Listener[T]) {m.lst[n] = append(m.lst[n], l)
}
BaseManager
提供了Add
方法用于添加監聽器和Invoke
方法用于觸發指定事件的監聽器。
具體事件管理器
下面是一個具體的事件管理器的示例實現:命令事件管理器。該管理器接收用戶從控制臺輸入的命令,并根據命令類型觸發相應的事件。
type Command struct {Kind stringArgs []string
}type CommandEventManager struct {BaseManager[*Command]
}func (m *CommandEventManager) Run() {var (inp stringargs Command)fmt.Scanln(&inp)cmd := strings.Split(inp, ":")if l := len(cmd); l == 0 {m.Invoke("no-command", nil)} else if l > 1 {args.Args = strings.Split(cmd[1], " ")}args.Kind = cmd[0]m.Invoke("any-command", &args)m.Invoke(args.Kind, &args)
}func NewCommandEventManager() Manager[*Command] {return &CommandEventManager{BaseManager: BaseManager[*Command]{lst: make(map[string][]Listener[*Command])},}
}
Run
方法獲取用戶從控制臺輸入的命令,并解析命令參數。如果沒有命令或者命令參數,則觸發"no-command"事件;否則,觸發"any-command"事件和具體命令的事件。
添加監聽器
讓我們向命令事件管理器添加一些監聽器。
func main() {cem := NewCommandEventManager()cem.Add("no-command", func(_ *Command) {fmt.Println("no command was recieved")})cem.Add("any-command", func(c *Command) {fmt.Printf("the %s command was executed", c.Kind)})cem.Add("sum", func(c *Command) {a, _ := strconv.Atoi(c.Args[0])b, _ := strconv.Atoi(c.Args[1])fmt.Printf("the sum result is: %d", a+b)})cem.Run()
}
在上面的示例中,程序只執行一次,但你可以將其放在一個無限循環中以持續監聽命令。
異步改進
可以將事件管理器的執行改為異步方式,以提高性能。每次執行事件時,可以將其作為一個goroutine
進行處理。甚至可以將每個監聽器的執行也放在一個goroutine
中,以提高并發性能。
通過上述改進,我們可以更好地利用Go語言的并發特性,提高事件處理效率。