在“通過通道”中實現事件偵聽器

這篇文章旨在解釋如何使用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()對於我可以處理的所有事件:barkpoophungry

一段時間後,我厭倦了撿便便,並雇了一個保姆去為我做事,但我仍然會告訴狗不要吠叫並餵他。

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">&lt;-</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">&lt;-</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, wont 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!


更多教程: