You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建可访问结构体值的事件处理器?附Go语言实现示例

事件处理器回调访问外部控制器信息的最优实现方式

我有一个名为"Instance"的控制器,它带有事件处理器管理器。另有若干类型不固定的其他控制器,这些控制器包含相关信息。当"Instance"控制器调用处理器函数时,回调函数必须能够访问其他控制器的信息。请问实现该需求的最佳方式是什么?我已有如下实现,但不确定是否为最优方案:

package main

import (
    "fmt"
    "time"
)

// ******************************************
type SetEvent func(val int)

type Instance struct {
    handlers []SetEvent
}

func NewInstance() *Instance {
    ins := Instance{}
    ins.handlers = make([]SetEvent, 0)
    return &ins
}

func (ins *Instance) AddHandler(handler SetEvent) {
    ins.handlers = append(ins.handlers, handler)
}

func (ins *Instance) Start() {
    go func() {
        i := 0
        for {
            for j := range ins.handlers {
                ins.handlers[j](i)
            }
            i++
            time.Sleep(time.Second)
        }
    }()
}

// *******************************************
type Instance2 struct {
    val int
}

func NewInstance2(val int) *Instance2 {
    ins := Instance2{}
    ins.val = val
    return &ins
}

// *******************************************
type Instance3 struct {
    str string
}

func NewInstance3(val string) *Instance3 {
    ins := Instance3{}
    ins.str = val
    return &ins
}

// *******************************************
func main() {
    b := NewInstance2(10)
    c := NewInstance3("Hello")

    a := NewInstance()

    a.AddHandler(func(val int) {
        fmt.Printf("Instance2.SetEvent %d / %d\n", val, b.val)
    })
    a.AddHandler(func(val int) {
        fmt.Printf("Instance3.SetEvent %d / %s\n", val, c.str)
    })

    a.Start()

    for {
        fmt.Printf("Main.run\n")
        time.Sleep(time.Second)
    }
}

方案评价与优化建议

你的现有实现是当前场景下的最优方案之一,核心是利用Go的闭包特性,在注册回调时直接捕获外部控制器实例(b、c),这种方式有以下优势:

  • 代码简洁直观,无需额外的依赖注入框架或复杂的上下文传递逻辑
  • 回调与目标控制器的关联关系清晰,可读性强
  • 天然支持不同类型的控制器,因为闭包可以捕获任意外部变量

如果后续需求扩展(比如需要动态替换控制器实例、多线程安全保障、更解耦的架构),可以考虑以下优化方向:

  • 依赖注入模式:定义一个包含所有需要访问的控制器的上下文结构体,在注册回调时将上下文传入,或者让Instance持有上下文引用。这种方式适合控制器实例需要动态变更的场景,但会增加一定的耦合度。
  • 事件总线模式:引入事件总线组件,让各个控制器自行订阅事件并关联自身信息。这种方式适合事件类型多、控制器数量庞大的复杂系统,能更好地解耦组件间的依赖。
  • 接口抽象:如果多个控制器存在共同行为,可以定义统一接口,让回调函数接受接口类型参数。但由于你提到控制器类型不固定,这种方式的适用性有限。

总结:在当前需求下,你的闭包实现已经足够高效且符合Go语言的设计习惯,无需过度设计。只有当需求复杂度提升时,再考虑引入更复杂的模式。

内容的提问来源于stack exchange,提问作者ExtremG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 07:27:36