Golang继承和方法重写

时间:2018-08-30 22:37:44

标签: inheritance go method-overriding

说明:我只是在学习GO,并且遇到了这个问题。

我正在尝试实现一个“类”,该类继承一个方法,该方法调用应该由子类实现的“虚拟”方法。这是我的代码:

https://play.golang.org/p/ysiaPwARkvl

package main

import (
    "fmt"
    "sync"
)

type Parent struct {
  sync.Mutex
  MyInterface
}

func (p *Parent) Foo() {
  p.Lock()
  defer p.Unlock()
  p.Bar()
}

func (p *Parent) B(){
  panic("NOT IMPLEMENTED")
}

func (p *Parent) A() {
  p.Lock()
  defer p.Unlock()
  p.B()
}

type MyInterface interface {
  Foo()
  Bar()
}

type Child struct {
  Parent
  Name string
}

func (c *Child) Bar(){
  fmt.Println(c.Name)
}

func (c *Child) B(){
  fmt.Println(c.Name)
}

func main() {
  c := new(Child)
  c.Name = "Child"
  // c.A() panic
  c.Foo() // pointer error
}

我遗漏了一些有关sync.Mutex的代码,该代码对异步的Child值进行了一些异步更新。

因此,显然在A()或Foo()中,指针p的类型为Parent。我应该如何更改代码,以便A / Foo引用Child类中定义的B / Bar?

1 个答案:

答案 0 :(得分:2)

当Go仅提供具有-a 关系(组成)时,您希望具有是-a 关系(继承性):

  • Go没有继承关系,因此两种类型之间没有 is-a 关系。 Child不是Parent的一种,因此指向Parent的指针不能保留指向Child的指针; Child 已包含 Parent

由于ParentChild之间没有 is-a 关系,因此Parent.Foo无法接收Child类型的对象,也不能它使用Child实现的任何方法。同样,这意味着Parent不能直接访问在Child上定义的任何方法,例如Bar()B()

通常,Parent不需要调用Child中的某些方法。如果是这样,您将为Parent方法传递一个参数,例如Child满足您通过该接口调用该方法的接口或调用Child方法的闭包:

// Use of an interface that Child satisfies.
type Beta interface {
    B()
}
func (p *Parent) A(b Beta) {
    p.Lock()
    defer p.Unlock()
    b.B()
}

// Use of a closure.
func (p *Parent) Foo(bar func()) {
    p.Lock()
    defer p.Unlock()
    bar()
}
func callFoo(p *Parent, c *Child) {
    callBar := func() {
        c.Bar()
    }
    p.Foo(callBar)
}

func (c *Child) Bar() {
    // stub
}

func (c *Child) B() {
    // stub
}

您获得的 Child可以免费调用Parent方法行为,但它看起来仅类似于继承。 child.Foo()实际上执行child.Parent.Foo(),这意味着Parent.Foo仍然收到Parent实例(因此得名),而不是Child实例。

但是,Parent无法访问Child未明确共享的有关Child的任何信息。接口和闭包可以充当类似于C ++中的friend关键字的两个类之间的机制,只是它们比friend关键字更具限制性。毕竟,Child不需要与Parent共享所有内容,而只需要共享它想要共享的位,有点类似于this pattern in C++。就我个人而言,我更喜欢使用接口,因为它允许您的Parent“类”使用满足共同接口的多种类型,使其与从普通函数或完全不相关的类型中调用方法几乎相同方法。