Go方式实现观察者设计模式

The Go way to implement the Observer design pattern

我的经验是使用 OOP 语言,但我已经开始尝试使用 Go。我无法找到在 Go 中实现 Observer design pattern 的最佳方法。

我按如下方式组织我的项目,其中 observers 文件夹中的所有内容都是 package observers 的一部分,subjects 文件夹中的所有内容都是 package subjects 的一部分。将观察者附加到主题是在 main.go.

中完成的
my-project/
  main.go
  observers/
    observer.go
    observer_one.go
    observer_two.go
  subjects/
    subject.go
    subject_one.go

我看过 this section in the Go wiki 接口:

Go interfaces generally belong in the package that uses values of the interface type, not the package that implements those values. The implementing package should return concrete (usually pointer or struct) types: that way, new methods can be added to implementations without requiring extensive refactoring.

牢记 Go Wiki 中的评论。我是这样实现的(省略了函数实现):

subject.go:

type ObserverInterface interface {
    Update(subject *Subject, updateType string)
}

type Subject struct {
    observers map[string][]ObserverInterface
}

func (s *Subject) Attach(observer ObserverInterface, updateType string) {}

func (s *Subject) Detach(observer ObserverInterface, updateType string) {}

func (s *Subject) notify(updateType string) {}

observer.go:

type SubjectInterface interface {
   Attach(observer Observer, updateType string)
   Detach(observer Observer, updateType string)
   notify(updateType string)
}

type Observer struct {
    uuid uuid.UUID
}

observer_one.go

type ObserverOne struct {
    Observer
}

func (o *ObserverOne) Update(subject *SubjectInterface, updateType string) {}

main.go

subjectOne := &SubjectOne{}
observerOne := &ObserverOne{Observer{uuid: uuid.New()}}
subjectOne.Attach(observerOne, "update_type")

我希望能够使用 SubjectInterface 作为 ObserverOneUpdate() 方法的参数,这样我就可以避免我的 subject 包和我的 observer 包,但出现以下编译时错误。

observers/observer_one.go:29:35: cannot use &observer (type *ObserverOne) as type subjects.ObserverInterface in argument to SubjectOne.Subject.Attach:
    *ObserverOne does not implement subjects.ObserverInterface (wrong type for Update method)
        have Update(*SubjectInterface, string)
        want Update(*subjects.Subject, string)

如果我将 observer_one.go 中 Update() 的定义替换为以下内容,它可以正常编译,但我认为我的想法是使用接口来解耦包:

func (o *ObserverOne) Update(subject *subjects.Subject, updateType string) {}

首先,不要使用指向接口的指针。

func (o *ObserverOne) Update(subject *SubjectInterface, updateType string) {}

应该是

func (o *ObserverOne) Update(subject SubjectInterface, updateType string) {}

其次,您已将接口定义为需要具体类型:

type ObserverInterface interface {
    Update(subject *Subject, updateType string)
}

相反,让它接受一个接口:

type ObserverInterface interface {
    Update(subject SubjectInterface, updateType string)
}

Flimzy 解决方案仍然将事物与显式接口联系在一起,形成 Observers 垂直抽象(即:ObserverInterface)。

更通用的版本可能如下所示:

package main

import (
    "fmt"
)

func main() {

    obs := Observer{SubjectObserver{}}

    s := Subject{Observer: obs}
    s.Update()

}

type Subject struct {
    Observer
    UUID string
}

func (s *Subject) Update() {
    s.Observer.Notify(s)
}

type SubjectObserver struct{}

func (s SubjectObserver) Notify(v interface{}) {
    x, ok := v.(*Subject)
    if ok {
        fmt.Printf("do whatever with %#v\n", x)
    }
}

type Observer []ObserverOf

func (o Observer) Notify(s interface{}) {
    for _, ob := range o {
        ob.Notify(s)
    }
}

type ObserverOf interface {
    Notify(interface{})
}

PO 嵌入观察者是一个细节。