go 新人,想写一个观察者模式。涉及到继承和重写。想请教一下大佬们.
流程就是,消费者监听用户的创建和删除事件
事件:
# 事件
type Event interface {
attach(observer Observer)
notifyAll()
}
//基础事件
type BaseEvent struct {
observers []Observer
msg interface{}
}
func (b *BaseEvent) attach(observer Observer) {
b.observers = append(b.observers, observer)
}
func (b *BaseEvent) notifyAll() {
for _, o := range b.observers {
o.Notify(b)
}
}
type User struct {
name string
}
//用户事件
type UserEvent struct {
BaseEvent
u User
}
func (u *UserEvent) Created() {
u.msg = fmt.Sprintf("user %s is created", u.u.name)
u.notifyAll()
}
func (u *UserEvent) Deleted() {
u.msg = fmt.Sprintf("user %s is Deleted", u.u.name)
u.notifyAll()
}
监听者
# 监听者定义
type Observer interface {
Notify(event Event)
addEvent(event Event)
}
type BaseObserver struct {
}
# 监听者基础
func (o *BaseObserver) addEvent(event Event) {
event.attach(o)
}
func (o *BaseObserver) Notify(event Event) {
fmt.Println("BaseObserver notify")
}
# 文档监听者
type DocumentObserver struct {
BaseObserver
}
func (d *DocumentObserver) Notify(event Event) {
e, ok := event.(*UserEvent)
if ok {
fmt.Println(e.msg)
}
}
测试代码
func TestDocumentObserver(t *testing.T) {
uEvent := &UserEvent{}
doObserver := &DocumentObserver{}
doObserver.addEvent(uEvent)
uEvent.Created()
}
结果
=== RUN TestDocumentObserver
BaseObserver notify
--- PASS: TestDocumentObserver (0.00s)
PASS
为什么,不会执行 Document 内部的代码,明明重写了父亲的方法额,应该如何修改呢
1
bruce0 2022-04-11 11:07:32 +08:00
DocumentObserver 应该是 需要 DocumentObserver 重写 addEvent(event Event), 因为
``` func (o *BaseObserver) addEvent(event Event) { event.attach(o) } ``` 这时候只是把 `BaseObserver` 放到 userEvent 中了, 后续 Notify 的时候 只会执行 BaseObserver 的 Notify |
2
Mitt 2022-04-11 11:07:44 +08:00
因为 addEvent 没重写
|
3
killerirving 2022-04-11 11:09:27 +08:00
DocumentObserver 没有实现 addEvent(),所以调用的是 BaseObserver 的 addEvent(), 这时 event.attach 接收到的 Observer 是 BaseObserver 这个实现。
|
4
frank1256 OP @killerirving
@Mitt @bruce0 我也猜测是这样的,但是我就是想让 DocumentObserver 去使用 BaseObserver 的 addEvent 方法,重写也是一样。就是为了减少代码,如果我重写,不就相当于 BaseObserver 没有用处吗 |
5
Mitt 2022-04-11 11:14:42 +08:00
@frank1256 golang 是没有继承的,不能用传统 OOP 语言思维去写,你其实应该写个方法接收两个 interface 来实现,这样就没问题了
|
6
bruce0 2022-04-11 11:18:10 +08:00
@frank1256 BaseObserver 中可以做一些默认的操作,或者通用的操作. 你这个问题有点像 子类可以执行父类的函数, 但是父类中无法执行子类的函数 那样
|
7
Mitt 2022-04-11 11:23:22 +08:00
@frank1256 #4 写个全局 map[Event]Observer ,然后写个 register(Event, Observer)去注册事件,然后 trigger(Event)就可以了,具体细节可以再考虑下
|
8
HUNYXV 2022-04-11 11:38:29 +08:00
可以看一下这个🌰
// Observable 被观察者接口 type Observable interface { Notify() } // Observer 观察者接口 type Observer interface { Update(*WeChatOfficialAccount) } var _ Observable = (*WeChatOfficialAccount)(nil) // WeChatOfficialAccount 微信公众号 type WeChatOfficialAccount struct { Name string NewArticle string subscriber []Observer } // NewWeChatOfficialAccount . func NewWeChatOfficialAccount(name string) *WeChatOfficialAccount { return &WeChatOfficialAccount{ Name: name, subscriber: make([]Observer, 0), } } // AddFollower . func (w *WeChatOfficialAccount) AddFollower(o Observer) { w.subscriber = append(w.subscriber, o) } // Publish 发布 func (w *WeChatOfficialAccount) Publish(newArticle string) { w.NewArticle = newArticle w.Notify() } // Notify 通知观察者们 func (w *WeChatOfficialAccount) Notify() { for _, s := range w.subscriber { s.Update(w) } } var _ Observer = (*WechatUser)(nil) // WechatUser wechat 用户 type WechatUser struct { Name string } func NewWechatUser(name string) *WechatUser { return &WechatUser{Name: name} } // Subscribe 订阅 func (u *WechatUser) Subscribe(woa *WeChatOfficialAccount) { woa.AddFollower(u) } // Update 接收通知 func (u *WechatUser) Update(w *WeChatOfficialAccount) { fmt.Printf("--------user: %s--------\n\t 微信公众号:%s 新文章:%s\n\n", u.Name, w.Name, w.NewArticle) } |
9
HUNYXV 2022-04-11 11:42:05 +08:00
# 文档监听者
type DocumentObserver struct { BaseObserver } func (d *DocumentObserver) Notify(event Event) { e, ok := event.(*UserEvent) if ok { fmt.Println(e.msg) } } ... doObserver := &DocumentObserver{} // 里面的 BaseObserver 好像没有实例化呀 🤔 |
10
28Sv0ngQfIE7Yloe 2022-04-11 11:42:48 +08:00
|
11
HUNYXV 2022-04-11 11:44:07 +08:00
抱歉。。。没看清。。。 是非指针类型的组合😓
|
12
viakiba 2022-04-11 12:00:14 +08:00
#### 抛砖引玉
```go //测试 package observer_test import ( "example.org/fanxing/observer" "fmt" "testing" ) func TestObserver(t *testing.T) { observer.ObserverInstance.Register("test", func(args observer.Event) { t.Log("test", args) fmt.Println("xxxxxxxx") }) observer.ObserverInstance.Register("test", func(args observer.Event) { t.Log("test", args) fmt.Println("YYYYYYYY") }) event := observer.LoginEvent{EventNameStr: "test", UserIdStr: "xxxx"} observer.ObserverInstance.Notify(event) } ``` ```go package observer // event 定义 type Event interface { EventName() string UserId() string } // event 例子 type LoginEvent struct { UserIdStr string EventNameStr string } func (loginEvent LoginEvent) EventName() string { return loginEvent.EventNameStr } func (loginEvent LoginEvent) UserId() string { return loginEvent.UserIdStr } // 事件监听 接口定义 type Observer interface { Register(string, ExecuteFunction) Notify(Event) } // 定义方法集合 type ExecuteFunction func(event Event) type ExecuteCollection struct { Collection []ExecuteFunction } type ObserverImpl struct { observers map[string]*ExecuteCollection } func (o ObserverImpl) Register(eventName string, executeFunction ExecuteFunction) { collection, ok := o.observers[eventName] if !ok { collection = &ExecuteCollection{} collection.Collection = append(collection.Collection, executeFunction) o.observers[eventName] = collection } else { collection.Collection = append(collection.Collection, executeFunction) } } func (o ObserverImpl) Notify(event Event) { collection, ok := o.observers[event.EventName()] if !ok { return } for _, function := range collection.Collection { function(event) } } var ObserverInstance ObserverImpl = ObserverImpl{ observers: make(map[string]*ExecuteCollection), } ``` |
13
tairan2006 2022-04-12 10:21:50 +08:00
go 一般是直接传入回调函数…
func doSomething(cbs ...func()) |