简体   繁体   English

在 Go 中是否有设计信号或事件 API 的首选方法?

[英]Is there a preferred way to design signal or event APIs in Go?

I am designing a package where I want to provide an API based on the observer pattern: that is, there are points where I'd like to emit a signal that will trigger zero or more interested parties.我正在设计一个包,我想在其中提供基于观察者模式的 API:也就是说,在某些点我想发出一个信号,触发零个或多个相关方。 Those interested parties shouldn't necessarily need to know about each other.那些感兴趣的各方不一定需要相互了解。

I know I can implement an API like this from scratch (eg using a collection of channels or callback functions), but was wondering if there was a preferred way of structuring such APIs.我知道我可以从头开始实现这样的 API(例如,使用一组通道或回调函数),但想知道是否有一种首选的方式来构建此类 API。

In many of the languages or frameworks I've played with, there has been standard ways to build these APIs so that they behave the way users expect: eg the g_signal_* functions for glib based applications, events and addEventListener() for JavaScript DOM apps, or multicast delegates for .NET.在我使用过的许多语言或框架中,都有构建这些 API 的标准方法,以便它们按照用户期望的方式运行:例如,用于基于 glib 的应用程序、事件的g_signal_*函数和用于 JavaScript DOM 应用程序的addEventListener()或 .NET 的多播委托。

Is there anything similar for Go? Go有没有类似的东西? If not, is there some other way of structuring this type of API that is more idiomatic in Go?如果没有,是否有其他方法可以构建这种在 Go 中更惯用的 API?

I would say that a goroutine receiving from a channel is an analogue of an observer to a certain extent.我会说从通道接收的 goroutine 在某种程度上类似于观察者。 An idiomatic way to expose events in Go would be thus IMHO to return channels from a package (function).因此,恕我直言,在 Go 中公开事件的惯用方法是从包(函数)返回通道。 Another observation is that callbacks are not used too often in Go programs.另一个观察结果是在 Go 程序中不经常使用回调。 One of the reasons is also the existence of the powerful select statement .原因之一也是强大的select statement的存在。

As a final note: some people (me too) consider GoF patterns as Go antipatterns.最后一点:有些人(我也是)将 GoF 模式视为 Go 反模式。

Go gives you a lot of tools for designing a signal api. Go 为您提供了很多用于设计信号 API 的工具。

First you have to decide a few things:首先,您必须决定几件事:

Do you want a push or a pull model?你想要推模型还是拉模型? eg.例如。 Does the publisher push events to the subscribers or do the subscribers pull events from the publisher?发布者是将事件推送给订阅者还是订阅者从发布者那里拉取事件?

If you want a push system then having the subscribers give the publisher a channel to send messages on would work really well.如果你想要一个推送系统,那么让订阅者给发布者一个发送消息的渠道会非常有效。 If you want a pull method then just a message box guarded with a mutex would work.如果你想要一个 pull 方法,那么只需要一个用互斥锁保护的消息框就可以了。 Other than that without knowing more about your requirements it's hard to give much more detail.除此之外,在不了解您的需求的情况下,很难提供更多细节。

I needed an "observer pattern" type thing in a couple of projects.我需要在几个项目中使用“观察者模式”类型的东西。 Here's a reusable example from a recent project. 是最近项目中的一个可重用示例

It's got a corresponding test that shows how to use it.它有一个相应的测试来展示如何使用它。

The basic theory is that an event emitter calls Submit with some piece of data whenever something interesting occurs.基本理论是,每当发生有趣的事情时,事件发射器都会使用一些数据调用Submit Any client that wants to be aware of that event will Register a channel it reads the event data off of.任何想要知道该事件的客户端都将Register一个它从中读取事件数据的通道。 This channel you registered can be used in a select loop, or you can read it directly (or buffer and poll it).您注册的这个频道可以在select循环中使用,或者您可以直接读取它(或缓冲并轮询它)。

When you're done, you Unregister .完成后,您Unregister

It's not perfect for all cases (eg I may want a force-unregister type of event for slow observers), but it works where I use it.它并不适用于所有情况(例如,我可能想要一个强制取消注册类型的事件用于慢速观察者),但它适用于我使用它的地方。

I would say there is no standard way of doing this because channels are built into the language.我会说没有标准的方法来做到这一点,因为通道是内置在语言中的。 There is no channel library with standard ways of doing things with channels, there are simply channels.没有频道库提供标准的频道做事方式,只有频道。 Having channels as built in first class objects frees you from having to work with standard techniques and lets you solve problems in the simplest most natural way.将通道内置在一流的对象中,您就不必使用标准技术,并让您以最简单最自然的方式解决问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM