Go 实现常用设计模式(四)观察者模式

观察者模式

Posted by 果果 on October 25, 2021

在电商网站中, 商品时不时地会出现缺货情况。 可能会有客户对于缺货的特定商品表现出兴趣。

这一问题有三种解决方案:

  • 客户以一定的频率查看商品的可用性。
  • 电商网站向客户发送有库存的所有新商品。
  • 客户只订阅其感兴趣的特定商品, 商品可用时便会收到通知。 同时, 多名客户也可订阅同一款产品。

选项 3 是最具可行性的, 这其实就是观察者模式的思想。 观察者模式的主要组成部分有:

  • 会在有任何事发生时发布事件的主体。
  • 订阅了主体事件并会在事件发生时收到通知的观察者。

subject.go: 主体

package main

type subject interface {
    register(Observer observer)
    deregister(Observer observer)
    notifyAll()
}

item.go: 具体主体

package main

import "fmt"

type item struct {
    observerList []observer
    name         string
    inStock      bool
}

func newItem(name string) *item {
    return &item{
        name: name,
    }
}
func (i *item) updateAvailability() {
    fmt.Printf("Item %s is now in stock\n", i.name)
    i.inStock = true
    i.notifyAll()
}
func (i *item) register(o observer) {
    i.observerList = append(i.observerList, o)
}

func (i *item) deregister(o observer) {
    i.observerList = removeFromslice(i.observerList, o)
}

func (i *item) notifyAll() {
    for _, observer := range i.observerList {
        observer.update(i.name)
    }
}

func removeFromslice(observerList []observer, observerToRemove observer) []observer {
    observerListLength := len(observerList)
    for i, observer := range observerList {
        if observerToRemove.getID() == observer.getID() {
            observerList[observerListLength-1], observerList[i] = observerList[i], observerList[observerListLength-1]
            return observerList[:observerListLength-1]
        }
    }
    return observerList
}

observer.go: 观察者

package main

type observer interface {
    update(string)
    getID() string
}

customer.go: 具体观察者

package main

import "fmt"

type customer struct {
    id string
}

func (c *customer) update(itemName string) {
    fmt.Printf("Sending email to customer %s for item %s\n", c.id, itemName)
}

func (c *customer) getID() string {
    return c.id
}

main.go: 客户端代码

package main

func main() {

    shirtItem := newItem("Nike Shirt")

    observerFirst := &customer{id: "[email protected]"}
    observerSecond := &customer{id: "[email protected]"}

    shirtItem.register(observerFirst)
    shirtItem.register(observerSecond)

    shirtItem.updateAvailability()
}

output.txt: 执行结果

Item Nike Shirt is now in stock
Sending email to customer [email protected] for item Nike Shirt
Sending email to customer [email protected] for item Nike Shirt