go - The Go way to implement the Observer design pattern
问题描述
My experience is with OOP languages but I've started trying out Go. I'm having trouble working out the best way to implement the Observer design pattern in Go.
I've organised my project as follows where everything in the observers
folder is part of package observers
and everything in the subjects
folder is part of package subjects
. The attaching of observers to subjects is done in main.go
.
my-project/
main.go
observers/
observer.go
observer_one.go
observer_two.go
subjects/
subject.go
subject_one.go
I've seen this section in the Go wiki about interfaces:
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.
Keeping the comment from the Go Wiki in mind. I've implemented like this (left out function implementations):
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")
I expect to be able to use SubjectInterface
for the argument to the Update()
method in ObserverOne
so that I can avoid having dependencies between my subject
package and my observer
package but I get the following compile-time error.
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)
If I replace the definition of Update()
in observer_one.go with the following it compiles fine but i thought the idea was to decouple the packages using interfaces:
func (o *ObserverOne) Update(subject *subjects.Subject, updateType string) {}
解决方案
First, don't use pointers to interfaces.
func (o *ObserverOne) Update(subject *SubjectInterface, updateType string) {}
should be
func (o *ObserverOne) Update(subject SubjectInterface, updateType string) {}
Second, you've defined your interface to require a concrete type:
type ObserverInterface interface {
Update(subject *Subject, updateType string)
}
Instead, make it accept an interface:
type ObserverInterface interface {
Update(subject SubjectInterface, updateType string)
}
推荐阅读
- excel - 递增不给出预期结果的语法
- r - ggplot 的功能:动态绘图的特定选择参数
- docker - 如何仅将 docker 容器暴露给专用网络
- c# - Microsoft.IdentityModel.Tokens 中的演员令牌是什么?
- python - 如何使 django 全球可用
- jquery - 如何从 Gridview 中的下拉列表中获取值并通过 ajax 和 jquery 将其传递给我的 Web 服务?
- c# - ASP.NET MVC 属性路由未命中正确的控制器
- r - 需要帮助滑块在 Shiny App 中工作
- python-3.x - 如何从具有 [5,5] 和 [10,10] 均值的高斯分布生成 2 组 1000 个 2D 点?
- spring-integration - Spring-Integration:多线程创建具有公共根目录的 sftp 目录失败