我的经验是使用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()
答案 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嵌入观察者是一个细节。