go 的继承和重写疑问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
frank1256
V2EX    Go 编程语言

go 的继承和重写疑问

  •  
  •   frank1256 2022-04-11 10:52:29 +08:00 2601 次点击
    这是一个创建于 1291 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 条附言    2022-04-11 14:00:33 +08:00
    知道啥情况了,addEvent 方法,是 baseObserver 实现的。所以事件维护的 slice 里放的是 baseObserver 类型,最后执行的也就是 base Observer 方法了。解决方法就是,将加入 event 的动作变成,由 event 自己触发。

    将测试方法改为

    ```go

    ```
    第 2 条附言    2022-04-11 14:00:52 +08:00
    改为

    func TestDocumentObserver(t *testing.T) {
    uEvent := &UserEvent{}
    doObserver := &DocumentObserver{}
    //doObserver.addEvent(uEvent)

    uEvent.Attach(doObserver)
    uEvent.Created()

    }
    第 3 条附言    2022-04-11 14:02:24 +08:00
    和 java 实现出来的结果,不太一样。java 可以将自身 this ,传递给 event ,并且接受到的类型是具体的实现即 documentObserve
    13 条回复    2022-04-12 10:21:50 +08:00
    bruce0
        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
    Mitt
        2
    Mitt  
       2022-04-11 11:07:44 +08:00
    因为 addEvent 没重写
    killerirving
        3
    killerirving  
       2022-04-11 11:09:27 +08:00
    DocumentObserver 没有实现 addEvent(),所以调用的是 BaseObserver 的 addEvent(), 这时 event.attach 接收到的 Observer 是 BaseObserver 这个实现。
    frank1256
        4
    frank1256  
    OP
       2022-04-11 11:13:22 +08:00
    @killerirving
    @Mitt
    @bruce0
    我也猜测是这样的,但是我就是想让 DocumentObserver 去使用 BaseObserver 的 addEvent 方法,重写也是一样。就是为了减少代码,如果我重写,不就相当于 BaseObserver 没有用处吗
    Mitt
        5
    Mitt  
       2022-04-11 11:14:42 +08:00
    @frank1256 golang 是没有继承的,不能用传统 OOP 语言思维去写,你其实应该写个方法接收两个 interface 来实现,这样就没问题了
    bruce0
        6
    bruce0  
       2022-04-11 11:18:10 +08:00
    @frank1256 BaseObserver 中可以做一些默认的操作,或者通用的操作. 你这个问题有点像 子类可以执行父类的函数, 但是父类中无法执行子类的函数 那样
    Mitt
        7
    Mitt  
       2022-04-11 11:23:22 +08:00
    @frank1256 #4 写个全局 map[Event]Observer ,然后写个 register(Event, Observer)去注册事件,然后 trigger(Event)就可以了,具体细节可以再考虑下
    HUNYXV
        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)
    }
    HUNYXV
        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 好像没有实例化呀
    HUNYXV
        11
    HUNYXV  
       2022-04-11 11:44:07 +08:00
    抱歉。。。没看清。。。 是非指针类型的组合
    viakiba
        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.Collectio {
    function(event)
    }
    }

    var ObserverInstance ObserverImpl = ObserverImpl{
    observers: make(map[string]*ExecuteCollection),
    }
    ```
    tairan2006
        13
    tairan2006  
       2022-04-12 10:21:50 +08:00
    go 一般是直接传入回调函数…

    func doSomething(cbs ...func())
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3184 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 79ms UTC 11:09 PVG 19:09 LAX 04:09 JFK 07:09
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86