go 的继承和重写疑问

2022-04-11 10:52:29 +08:00
 frank1256

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 内部的代码,明明重写了父亲的方法额,应该如何修改呢

2287 次点击
所在节点    Go 编程语言
13 条回复
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
Mitt
2022-04-11 11:07:44 +08:00
因为 addEvent 没重写
killerirving
2022-04-11 11:09:27 +08:00
DocumentObserver 没有实现 addEvent(),所以调用的是 BaseObserver 的 addEvent(), 这时 event.attach 接收到的 Observer 是 BaseObserver 这个实现。
frank1256
2022-04-11 11:13:22 +08:00
@killerirving
@Mitt
@bruce0
我也猜测是这样的,但是我就是想让 DocumentObserver 去使用 BaseObserver 的 addEvent 方法,重写也是一样。就是为了减少代码,如果我重写,不就相当于 BaseObserver 没有用处吗
Mitt
2022-04-11 11:14:42 +08:00
@frank1256 golang 是没有继承的,不能用传统 OOP 语言思维去写,你其实应该写个方法接收两个 interface 来实现,这样就没问题了
bruce0
2022-04-11 11:18:10 +08:00
@frank1256 BaseObserver 中可以做一些默认的操作,或者通用的操作. 你这个问题有点像 子类可以执行父类的函数, 但是父类中无法执行子类的函数 那样
Mitt
2022-04-11 11:23:22 +08:00
@frank1256 #4 写个全局 map[Event]Observer ,然后写个 register(Event, Observer)去注册事件,然后 trigger(Event)就可以了,具体细节可以再考虑下
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)
}
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 好像没有实例化呀 🤔
28Sv0ngQfIE7Yloe
2022-04-11 11:42:48 +08:00
HUNYXV
2022-04-11 11:44:07 +08:00
抱歉。。。没看清。。。 是非指针类型的组合😓
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),
}
```
tairan2006
2022-04-12 10:21:50 +08:00
go 一般是直接传入回调函数…

func doSomething(cbs ...func())

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/846220

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX