这篇文章旨在解释如何使用Go通道实现事件侦听器,即所谓的设计模式术语中的观察者。
问题
我有一只有时会吠叫的狗,这种情况发生时,我通常会告诉他不要吠叫。和所有的狗一样,他有时会大便,所以我需要捡起来。
我将把我的狗建模为具有事件侦听器列表的结构,这是照顾他的人的列表。
当事情发生时,狗会向那些听众发出事件。
这是我们在Go中为狗建模的方式:我们有一个带有名称和看护者列表的结构,以及3个事件:我们可以添加一个新的保姆,可以删除一个保姆,并且我们的狗可以发出事件。
// Dog has a name and a list of people caring for him and watching
// what he does
type Dog struct {
name string
sitters map[string][]chan string
}
// AddSitter adds an event listener to the Dog struct instance
func (b *Dog) AddSitter(e string, ch chan string) {
if b.sitters == nil {
b.sitters = make(map[string][]chan string)
}
if _, ok := b.sitters[e]; ok {
b.sitters[e] = append(b.sitters[e], ch)
} else {
b.sitters[e] = []chan string{ch}
}
}
// RemoveSitter removes an event listener from the Dog struct instance
func (b *Dog) RemoveSitter(e string, ch chan string) {
if _, ok := b.sitters[e]; ok {
for i := range b.sitters[e] {
if b.sitters[e][i] == ch {
b.sitters[e] = append(b.sitters[e][:i], b.sitters[e][i+1:]…)
break
}
}
}
}
// Emit emits an event on the Dog struct instance
func (b *Dog) Emit(e string, response string) {
if , ok := b.sitters[e]; ok {
for , handler := range b.sitters[e] {
go func(handler chan string) {
handler <- response
}(handler)
}
}
}
到处乱跑我们的狗
让我们将狗带入世界,看看它是如何工作的。首先,我是唯一照顾狗的人,所以我将自己添加为狗的保姆balto.AddSitter()
对于我可以处理的所有事件:bark
,poop
,hungry
。
一段时间后,我厌倦了捡便便,并雇了一个保姆去为我做事,但我仍然会告诉狗不要吠叫并喂他。
package main
import (
“fmt”
“time”
)
func main() {
balto := Dog{“Balto”, nil}
<span style="color:#a6e22e">flavio</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">string</span>)
<span style="color:#a6e22e">balto</span>.<span style="color:#a6e22e">AddSitter</span>(<span style="color:#e6db74">"bark"</span>, <span style="color:#a6e22e">flavio</span>)
<span style="color:#a6e22e">balto</span>.<span style="color:#a6e22e">AddSitter</span>(<span style="color:#e6db74">"poop"</span>, <span style="color:#a6e22e">flavio</span>)
<span style="color:#a6e22e">balto</span>.<span style="color:#a6e22e">AddSitter</span>(<span style="color:#e6db74">"hungry"</span>, <span style="color:#a6e22e">flavio</span>)
<span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>() {
<span style="color:#66d9ef">for</span> {
<span style="color:#a6e22e">msg</span> <span style="color:#f92672">:=</span> <span style="color:#f92672"><-</span><span style="color:#a6e22e">flavio</span>
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"Flavio: "</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">msg</span>)
}
}()
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"The dog barked!"</span>)
<span style="color:#a6e22e">balto</span>.<span style="color:#a6e22e">Emit</span>(<span style="color:#e6db74">"bark"</span>, <span style="color:#e6db74">"Told not to bark!"</span>)
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"The dog pooped!"</span>)
<span style="color:#a6e22e">balto</span>.<span style="color:#a6e22e">Emit</span>(<span style="color:#e6db74">"poop"</span>, <span style="color:#e6db74">"Picked up poop!"</span>)
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"The dog is hungry!"</span>)
<span style="color:#a6e22e">balto</span>.<span style="color:#a6e22e">Emit</span>(<span style="color:#e6db74">"hungry"</span>, <span style="color:#e6db74">"Feed the dog!"</span>)
<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Sleep</span>(<span style="color:#ae81ff">3</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>)
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">"\n.\n.\n.\n"</span>)
<span style="color:#a6e22e">balto</span>.<span style="color:#a6e22e">RemoveSitter</span>(<span style="color:#e6db74">"poop"</span>, <span style="color:#a6e22e">flavio</span>)
<span style="color:#75715e">// Hired a dog sitter to pick up poop
dogsitter := make(chan string)
balto.AddSitter(“poop”, dogsitter)
fmt.Println(“Flavio hired a dogsitter to pick up poop, won’t pick it up again”)
<span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>() {
<span style="color:#66d9ef">for</span> {
<span style="color:#a6e22e">msg</span> <span style="color:#f92672">:=</span> <span style="color:#f92672"><-</span><span style="color:#a6e22e">dogsitter</span>
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"Dogsitter: "</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">msg</span>)
}
}()
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"Dog barked!"</span>)
<span style="color:#a6e22e">balto</span>.<span style="color:#a6e22e">Emit</span>(<span style="color:#e6db74">"bark"</span>, <span style="color:#e6db74">"Told not to bark!"</span>)
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"Dog has pooped!"</span>)
<span style="color:#a6e22e">balto</span>.<span style="color:#a6e22e">Emit</span>(<span style="color:#e6db74">"poop"</span>, <span style="color:#e6db74">"Picked up poop!"</span>)
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"Dog has pooped again!"</span>)
<span style="color:#a6e22e">balto</span>.<span style="color:#a6e22e">Emit</span>(<span style="color:#e6db74">"poop"</span>, <span style="color:#e6db74">"Picked up poop, again!"</span>)
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"The dog is hungry!"</span>)
<span style="color:#a6e22e">balto</span>.<span style="color:#a6e22e">Emit</span>(<span style="color:#e6db74">"hungry"</span>, <span style="color:#e6db74">"Feed the dog!"</span>)
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Scanln</span>()
}
我正在使用fmt.Scanln()
最后防止程序退出时main()
已经结束,同时仍在等待goroutines处理事件完成。
如果我管理它,看来我们的新员工也在做我们期望他做的工作,我们可以放松一下:
$ go run eventlistener.go
The dog barked!
The dog pooped!
The dog is hungry!
Flavio: Picked up poop!
Flavio: Told not to bark!
Flavio: Feed the dog!
.
.
.
Flavio hired a dogsitter to pick up poop, won’t pick it up again
Dog barked!
Dog has pooped!
Dog has pooped again!
The dog is hungry!
Flavio: Told not to bark!
Dogsitter: Picked up poop!
Dogsitter: Picked up poop, again!
Flavio: Feed the dog!
更多教程:
- 使用NGINX反向代理服务Go服务
- 在Go中复制结构
- Go Web服务器的基础
- 在Go中对地图类型进行排序
- 简而言之去指针
- 转到标签说明
- 开始日期和时间格式
- 使用Go进行JSON处理
- 可变参数函数
- 去弦备忘单
- 转到空界面说明
- 使用VS Code和Delve调试Go
- 命名为Go返回参数
- 在Go中生成随机数和字符串
- Go项目的文件系统结构
- Go中的二进制搜索算法
- 在Go中使用命令行标志
- GOPATH解释
- 使用Go构建一个命令行应用程序:lolcat
- 使用Go构建CLI命令:Cowsay
- 在Go中使用壳管
- Go CLI教程:财富克隆
- 使用Go列出文件夹中的文件
- 使用Go从GitHub获取存储库列表
- 去,将一小段字符串附加到文件中
- 去,将字符串转换为字节片
- 使用Go可视化您本地的Git贡献
- Go CPU和内存分析入门
- 解决Go程序中的“不支持索引”错误
- 测量Go程序中的执行时间
- 使用Go构建Web爬网程序以检测重复的标题
- 最佳实践:指针还是价值接收者?
- 最佳实践:您应该使用方法还是函数?
- Go数据结构:集
- 前往地图备忘单
- 在Go中生成泛型类型的实现
- Go数据结构:字典
- Go数据结构:哈希表
- 在“通过通道”中实现事件侦听器
- Go数据结构:堆栈
- Go数据结构:队列
- Go数据结构:二进制搜索树
- Go数据结构:图形
- Go数据结构:链表
- Go数据结构的完整指南
- 比较Go值
- Go是面向对象的吗?
- 在Go中使用SQL数据库
- 在Go中使用环境变量
- 上篇教程:PostgreSQL支持的REST API
- 在Go Web服务器上启用CORS
- 在Docker容器中部署Go应用程序
- 为什么Go是作为PHP开发人员学习的功能强大的语言
- 去,删除io.Reader.ReadString换行符
- 开始,如何观看更改并重建程序
- 去算一下自约会以来的月份
- 在Go中访问HTTP POST参数