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
作为 ObserverOne
中 Update()
方法的参数,这样我就可以避免我的 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 嵌入观察者是一个细节。
我的经验是使用 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
作为 ObserverOne
中 Update()
方法的参数,这样我就可以避免我的 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 嵌入观察者是一个细节。