Go语言中的观察者模式

发布于 2024-09-24 00:33:33 字数 139 浏览 3 评论 0原文

这个问题很常见:​​当某个事件发生时,一个对象应该通知它的所有订阅者。在 C++ 中,我们可以使用 boost::signals 或其他东西。但是用 Go 语言如何做到这一点呢?很高兴看到一些工作代码示例,其中几个对象订阅了发布者并处理通知。

谢谢

This problem is pretty common: an object should notify all its subscribers when some event occurs. In C++ we may use boost::signals or something else. But how to do this in Go language? It would be nice to see some working code example where a couple of objects are subscribed to a publisher and process notifications.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甜味拾荒者 2024-10-01 00:33:33

这在 Go 中实际上非常简单。使用渠道。这就是它们的用途。

type Publish struct {
    listeners []chan *Msg
}

type Subscriber struct {
    Channel chan *Msg
}

func (p *Publisher) Sub(c chan *Msg) {
    p.appendListener(c)
}

func (p *Publisher) Pub(m *Msg) {
    for _, c := range p.listeners {
        c <- Msg
    }
}

func (s *Subscriber) ListenOnChannel() {
    for {
        data := <-s.Channel
        //Process data
    }
}

func main() {
    for _, v := range subscribers {
        p.Sub(v.Channel)
        go v.ListenOnChannel()
    }
    //Some kind of wait here
}

显然这不完全是一个有效的代码示例。但已经很接近了。

This is actually pretty simple in Go. Use channels. This is the kind of thing they're made for.

type Publish struct {
    listeners []chan *Msg
}

type Subscriber struct {
    Channel chan *Msg
}

func (p *Publisher) Sub(c chan *Msg) {
    p.appendListener(c)
}

func (p *Publisher) Pub(m *Msg) {
    for _, c := range p.listeners {
        c <- Msg
    }
}

func (s *Subscriber) ListenOnChannel() {
    for {
        data := <-s.Channel
        //Process data
    }
}

func main() {
    for _, v := range subscribers {
        p.Sub(v.Channel)
        go v.ListenOnChannel()
    }
    //Some kind of wait here
}

Obviously this isn't exactly a working code sample. But it's close.

£噩梦荏苒 2024-10-01 00:33:33

这里我给出了一个没有通道的经典实现,请随意参考这个 帖子
输入图片此处描述

假设示例:
假设您对股票市场感兴趣。您有以下需求: 您想要跟踪特定公司(例如 Apple Inc)的股票价格。您不想错过任何股票价格更新,尤其是当价格跌至某个点时。您希望收到所有股票价格更新的通知。

接口:

// Subject interface
type Subject interface {
    Attach(o Observer) (bool, error)
    Detach(o Observer) (bool, error)
    Notify() (bool, error)
}

// Observer Interface
type Observer interface {
    Update(string)
}

具体观察者对象

// Concrete Observer: StockObserver
type StockObserver struct {
    name string
}

func (s *StockObserver) Update(t string) {
    // do something
    println("StockObserver:", s.name, "has been updated,", "received subject string:", t)
}

具体主体对象

// Concrete Subject: stockMonitor
type StockMonitor struct {
    // internal state
    ticker string
    price  float64

    observers []Observer
}

func (s *StockMonitor) Attach(o Observer) (bool, error) {

    for _, observer := range s.observers {
        if observer == o {
            return false, errors.New("Observer already exists")
        }
    }
    s.observers = append(s.observers, o)
    return true, nil
}

func (s *StockMonitor) Detach(o Observer) (bool, error) {

    for i, observer := range s.observers {
        if observer == o {
            s.observers = append(s.observers[:i], s.observers[i+1:]...)
            return true, nil
        }
    }
    return false, errors.New("Observer not found")
}

func (s *StockMonitor) Notify() (bool, error) {
    for _, observer := range s.observers {
        observer.Update(s.String())
    }
    return true, nil
}

func (s *StockMonitor) SetPrice(price float64) {
    s.price = price
    s.Notify()
}

func (s *StockMonitor) String() string {
    convertFloatToString := strconv.FormatFloat(s.price, 'f', 2, 64)
    return "StockMonitor: " + s.ticker + " $" + convertFloatToString
}

main.go


func main() {

    // Create a new stockMonitor object
    stockMonitor := &StockMonitor{
        ticker: "AAPL",
        price:  0.0,
    }

    observerA := &StockObserver{
        name: "Observer A",
    }
    observerB := &StockObserver{
        name: "Observer B",
    }

    // Attach our Observers to the stockMonitor
    stockMonitor.Attach(observerA)
    stockMonitor.Attach(observerB)

    // Start the stockMonitor
    stockMonitor.Notify()

    // Change the price of the stockMonitor
    stockMonitor.SetPrice(500)

    // Detach an Observer from the stockMonitor
    stockMonitor.Detach(observerA)

    // Change the price of the stockMonitor
    stockMonitor.SetPrice(528)
}

在这部分

  • 我们创建两个观察者,观察者A和观察者B。
    将它们附加到 stockMonitor。
  • 更改 stockMonitor 的价格。
  • 我们看到观察者A和观察者B都收到了通知。
  • 从 stockMonitor 中分​​离观察者 A 并更改股票价格。我们可以看到只有observerB收到通知。

Here I give a classific implementation without channels, be free to refer this post
enter image description here

Assumed Example:
Suppose you are interested in the stock market. You have the following needs: You want to keep track of the stock prices of a particular company (e.g. Apple Inc). You would not like to miss any stock price update especially if the price is dropping to a certain point. You would like to be notified of all the stock price updates.

interfaces:

// Subject interface
type Subject interface {
    Attach(o Observer) (bool, error)
    Detach(o Observer) (bool, error)
    Notify() (bool, error)
}

// Observer Interface
type Observer interface {
    Update(string)
}

Concrete Observer object

// Concrete Observer: StockObserver
type StockObserver struct {
    name string
}

func (s *StockObserver) Update(t string) {
    // do something
    println("StockObserver:", s.name, "has been updated,", "received subject string:", t)
}

Concrete Subject object

// Concrete Subject: stockMonitor
type StockMonitor struct {
    // internal state
    ticker string
    price  float64

    observers []Observer
}

func (s *StockMonitor) Attach(o Observer) (bool, error) {

    for _, observer := range s.observers {
        if observer == o {
            return false, errors.New("Observer already exists")
        }
    }
    s.observers = append(s.observers, o)
    return true, nil
}

func (s *StockMonitor) Detach(o Observer) (bool, error) {

    for i, observer := range s.observers {
        if observer == o {
            s.observers = append(s.observers[:i], s.observers[i+1:]...)
            return true, nil
        }
    }
    return false, errors.New("Observer not found")
}

func (s *StockMonitor) Notify() (bool, error) {
    for _, observer := range s.observers {
        observer.Update(s.String())
    }
    return true, nil
}

func (s *StockMonitor) SetPrice(price float64) {
    s.price = price
    s.Notify()
}

func (s *StockMonitor) String() string {
    convertFloatToString := strconv.FormatFloat(s.price, 'f', 2, 64)
    return "StockMonitor: " + s.ticker + " 
quot; + convertFloatToString
}

main.go


func main() {

    // Create a new stockMonitor object
    stockMonitor := &StockMonitor{
        ticker: "AAPL",
        price:  0.0,
    }

    observerA := &StockObserver{
        name: "Observer A",
    }
    observerB := &StockObserver{
        name: "Observer B",
    }

    // Attach our Observers to the stockMonitor
    stockMonitor.Attach(observerA)
    stockMonitor.Attach(observerB)

    // Start the stockMonitor
    stockMonitor.Notify()

    // Change the price of the stockMonitor
    stockMonitor.SetPrice(500)

    // Detach an Observer from the stockMonitor
    stockMonitor.Detach(observerA)

    // Change the price of the stockMonitor
    stockMonitor.SetPrice(528)
}

In this part

  • We create two observers, observerA and observerB.
    Attach them to the stockMonitor.
  • Change the price of the stockMonitor.
  • We see that observerA and obsererB are both notified.
  • Detach observerA from the stockMonitor and change the stock price. We can see that only observerB is notified.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文