douyun1972 2019-07-14 11:47
浏览 107
已采纳

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

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) {}
  • 写回答

2条回答 默认 最新

  • duanchan9354 2019-07-14 12:02
    关注

    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)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 LiBeAs的带隙等于0.997eV,计算阴离子的N和P
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 来真人,不要ai!matlab有关常微分方程的问题求解决,
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算