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

时间:2019-07-14 11:47:37

标签: go design-patterns observer-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接口通常属于使用接口类型的值的程序包,而不是实现这些值的程序包。该实现程序包应返回具体的(通常是指针或结构)类型:这样,可以在无需大量重构的情况下将新方法添加到实现中。

牢记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作为Update()ObserverOne方法的参数,以便避免在subject包和{ {1}}程序包,但出现以下编译时错误。

observer

如果我用以下内容替换observer_one.go中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) 的定义,它可以很好地编译,但我认为这种想法是使用接口解耦程序包:

Update()

2 个答案:

答案 0 :(得分:4)

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

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)
}

答案 1 :(得分:-2)

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嵌入观察者是一个细节。