Golang:创建一个接口来抽象可能具有可变参数的方法

我写了一些创造“人类”的代码。人类每 100 毫秒过一次生日,您可以像这样订阅事件:


    pers1 := new(Human)

    pers1.Init("John")


    pers1.Subscribe(func(h Human) { fmt.Printf("Observer1 : %s", h.String()); return })

    pers1.Subscribe(func(h Human) { fmt.Printf("Observer2 : %s", h.String()); return })


    time.Sleep(3 * time.Second)

输出如下


HUMAN John is born  // by init

HUMAN John is now followed by 0x4901a0   // by subscribe

There is now 1 observers

HUMAN John is now followed by 0x490300   // by subscribe

There is now 2 observers


[T+0100ms]


HUMAN John has its birthday      // after 100ms : birthday happens

Observer1 : HUMAN : John is 1   // callback

Observer2 : HUMAN : John is 1   // callback

// ... continue for 3 seconds

详细代码在这里,但问题不在 https://goplay.tools/snippet/7qsZ1itcqrS


我的问题如下:


我想创建一个接口Producer对应于产生我可以订阅的事件的事物。


您可以订阅:


过生日的人

可检测湿度变化的湿度传感器

收到邮件的邮件服务器...

在我的例子中,回调函数有一个参数:一个Human。那个年龄变了...


以相同的方式,湿度传感器的给定事件将期望传感器结构。


我的问题是


我认为这样做有意义吗?(这是一个学者问题,没有工作)

如果是,如何。我找不到相关的例子

那将是


type Producer interface{ 

     Subscribe( func( < something variable >) )

}

我无法得到一些工作。我也很难为这个问题找到一个好的标题。随意给我一个更好的。


慕丝7291255
浏览 125回答 1
1回答

波斯汪

根据您的需要,此处提供三个可能适合您的选项。选项 1:已发布项目的通用界面不仅为可以拥有订阅者的发布者创建一个接口,而且为那些发布者可以发布的东西创建一个接口:type Item interface{&nbsp; Description() string&nbsp; Age() int}type human struct{&nbsp; age int}func (h *human) Description() string {&nbsp; return "human"}func (h *human) Age() int {&nbsp; return h.age}type Publisher interface{&nbsp; Subscribe(func(Item))}type humanProducer struct{&nbsp; subscribers []func(Item)}func (hp *humanProducer) Subscribe(f func(Item) {&nbsp; hp.subscribers = append(hp.subscribers, f)}// Example usefunc addSubscriber(p Publisher, f func(Item)) {&nbsp; p.Subscribe(f)}func main() {&nbsp; hp := &humanProducer{}&nbsp; addSubscriber(p, func(i Item) {&nbsp; &nbsp; fmt.Printf("Got a %s that is %d years old.\n", i.Description(), i.Age())&nbsp; })}您现在可以通过让它们实现接口来设置要发布的其他类型的东西Item。这里的和方法只是示例——您可以在其中添加任何您需要的方法Description。Age优点避免反射。避免类型参数;适用于 Go 1.18 之前的版本。订阅者可以接收多种项目。发布者可以发布多种项目。缺点已发布的项目不能只是任何东西——您必须定义一组预先确定的功能,所有类型的已发布项目都必须具有这些功能。已发布的项目隐藏在界面后面,因此您只能使用界面中公开的功能Item,除非您开始强制转换或使用反射。选项 2:使用类型参数的接口将类型参数添加到接口本身:type human struct{&nbsp; age int}type Publisher[T any] interface{&nbsp; Subscribe(func(T))}type humanProducer struct{&nbsp; subscribers []func(*human)}func (hp *humanProducer) Subscribe(f func(*human) {&nbsp; hp.subscribers = append(hp.subscribers, f)}// Example usefunc addSubscriber[T any](p Publisher[T], f func(T)) {&nbsp; p.Subscribe(f)}func main() {&nbsp; hp := &humanProducer{}&nbsp; addSubscriber[*human](p, func(h *human) {&nbsp; &nbsp; fmt.Printf("Got a human that is %d years old.\n", h.age)&nbsp; })}优点避免反射。对可以发布的内容没有限制。已发布的项目不会隐藏在界面后面。缺点发布者只能发布一种特定类型的项目。订户只能收到一种特定的物品。接口的任何使用都Publisher需要使用类型参数。仅适用于 Go 1.18 或更高版本。选项 3:反射/铸造允许发布者发布任何内容,并在订阅者中使用反射或强制转换来确定发布的内容类型:type human struct{&nbsp; age int}type Publisher interface{&nbsp; Subscribe(func(any))}type humanProducer struct{&nbsp; subscribers []func(any)}func (hp *humanProducer) Subscribe(f func(any) {&nbsp; hp.subscribers = append(hp.subscribers, f)}// Example usefunc addSubscriber(p Publisher, f func(any)) {&nbsp; p.Subscribe(f)}func main() {&nbsp; hp := &humanProducer{}&nbsp; addSubscriber(p, func(i any) {&nbsp; &nbsp; if h, ok := any.(*human); ok {&nbsp; &nbsp; &nbsp; fmt.Printf("Got a human that is %d years old.\n", h.age)&nbsp; &nbsp; }&nbsp; })}如果使用 1.18 之前的 Go,请替换any为interface{}.&nbsp;此选项与选项 1 有点相同,只是Item接口为空。优点避免类型参数;适用于 Go 1.18 之前的版本。对可以发布的内容没有限制。已发布的项目不会隐藏在界面后面。订阅者可以接收多种项目。发布者可以发布多种项目。缺点需要反射或投射,这是缓慢、笨拙且不太安全的。订户将不得不做额外的工作来弄清楚他们收到了什么样的项目。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go