Golang Go语言中的继承和重写疑问
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 内部的代码,明明重写了父亲的方法额,应该如何修改呢
Golang Go语言中的继承和重写疑问
更多关于Golang Go语言中的继承和重写疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
DocumentObserver 应该是 需要 DocumentObserver 重写 addEvent(event Event), 因为 <br>func (o *BaseObserver) addEvent(event Event) {<br> event.attach(o)<br>}<br>
这时候只是把 BaseObserver
放到 userEvent 中了, 后续 Notify 的时候 只会执行 BaseObserver 的 Notify
更多关于Golang Go语言中的继承和重写疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
因为 addEvent 没重写
DocumentObserver 没有实现 addEvent(),所以调用的是 BaseObserver 的 addEvent(), 这时 event.attach 接收到的 Observer 是 BaseObserver 这个实现。
我也猜测是这样的,但是我就是想让 DocumentObserver 去使用 BaseObserver 的 addEvent 方法,重写也是一样。就是为了减少代码,如果我重写,不就相当于 BaseObserver 没有用处吗
golang 是没有继承的,不能用传统 OOP 语言思维去写,你其实应该写个方法接收两个 interface 来实现,这样就没问题了
BaseObserver 中可以做一些默认的操作,或者通用的操作. 你这个问题有点像 子类可以执行父类的函数, 但是父类中无法执行子类的函数 那样
#4 写个全局 map[Event]Observer ,然后写个 register(Event, Observer)去注册事件,然后 trigger(Event)就可以了,具体细节可以再考虑下
可以看一下这个🌰
// 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)
}
文档监听者
type DocumentObserver struct {
BaseObserver
}
func (d *DocumentObserver) Notify(event Event) {
e, ok := event.(*UserEvent)
if ok {
fmt.Println(e.msg)
}
}
…
doObserver := &DocumentObserver{} // 里面的 BaseObserver 好像没有实例化呀 🤔
抱歉。。。没看清。。。 是非指针类型的组合😓
抛砖引玉
go<br>//测试<br>package observer_test<br><br>import (<br> "<a target="_blank" href="http://example.org/fanxing/observer" rel="nofollow noopener">example.org/fanxing/observer</a>"<br> "fmt"<br> "testing"<br>)<br><br>func TestObserver(t *testing.T) {<br> observer.ObserverInstance.Register("test", func(args observer.Event) {<br> t.Log("test", args)<br> fmt.Println("xxxxxxxx")<br> })<br> observer.ObserverInstance.Register("test", func(args observer.Event) {<br> t.Log("test", args)<br> fmt.Println("YYYYYYYY")<br> })<br> event := observer.LoginEvent{EventNameStr: "test", UserIdStr: "xxxx"}<br> observer.ObserverInstance.Notify(event)<br>}<br><br>
go<br>package observer<br><br>// event 定义<br>type Event interface {<br> EventName() string<br> UserId() string<br>}<br><br>// event 例子<br>type LoginEvent struct {<br> UserIdStr string<br> EventNameStr string<br>}<br><br>func (loginEvent LoginEvent) EventName() string {<br> return loginEvent.EventNameStr<br>}<br><br>func (loginEvent LoginEvent) UserId() string {<br> return loginEvent.UserIdStr<br>}<br><br>// 事件监听 接口定义<br>type Observer interface {<br> Register(string, ExecuteFunction)<br><br> Notify(Event)<br>}<br><br>// 定义方法集合<br>type ExecuteFunction func(event Event)<br><br>type ExecuteCollection struct {<br> Collection []ExecuteFunction<br>}<br><br>type ObserverImpl struct {<br> observers map[string]*ExecuteCollection<br>}<br><br>func (o ObserverImpl) Register(eventName string, executeFunction ExecuteFunction) {<br> collection, ok := o.observers[eventName]<br> if !ok {<br> collection = &ExecuteCollection{}<br> collection.Collection = append(collection.Collection, executeFunction)<br> o.observers[eventName] = collection<br> } else {<br> collection.Collection = append(collection.Collection, executeFunction)<br> }<br>}<br><br>func (o ObserverImpl) Notify(event Event) {<br> collection, ok := o.observers[event.EventName()]<br> if !ok {<br> return<br> }<br> for _, function := range collection.Collection {<br> function(event)<br> }<br>}<br><br>var ObserverInstance ObserverImpl = ObserverImpl{<br> observers: make(map[string]*ExecuteCollection),<br>}<br>
go 一般是直接传入回调函数…
func doSomething(cbs …func())
在Go语言中,并没有传统面向对象编程语言(如Java或C++)中直接的“继承”机制。Go采用的是组合(Composition)的方式来实现代码复用,而不是继承。这种方式通过将一个结构体嵌入到另一个结构体中来实现。
关于重写(Override),在Go中,虽然没有“方法重写”的术语,但你可以通过定义与嵌入结构体中同名的方法来实现某种形式的行为覆盖。这实际上是一种“方法遮蔽”(Method Shadowing)现象。
当你定义一个结构体,并嵌入另一个结构体时,如果你在当前结构体中定义了一个与嵌入结构体中方法同名的方法,那么调用该方法时,会优先使用当前结构体中定义的方法,从而实现了对嵌入结构体中同名方法的覆盖效果。
需要注意的是,这种“覆盖”并不改变嵌入结构体的方法表,而只是在当前作用域内提供了一种新的方法实现。此外,由于Go没有多态的概念(即没有基于类型的动态方法调用),这种“覆盖”主要体现在编译时的静态解析上。
总之,虽然Go语言没有直接的继承和重写机制,但通过组合和方法遮蔽,你可以实现类似的代码复用和行为定制效果。这种设计哲学体现了Go语言的简洁性和实用性。