猿问

在这种特定情况下,在 Go 中模仿继承的最惯用的方法是什么?

我一直在想很多关于我遇到的这个特殊问题,我应该如何以最干净的方式解决它。


想象一个看起来像这样的应用程序:


type AreaCalculator interface {

  Area() int

}


type Rectangle struct {

    color  string

    width  int

    height int

}


type (r *Rectangle) Area() int {

   return r.width * r.height

}


type Circle struct {

    color    string

    diameter int

}


type (c *Circle) Area() int {

   return r.diameter / 2 * r.diameter / 2 * π

}


type Canvas struct {

    children []AreaCalculator

}


func (c *Canvas) String() {

    for child := range c.children {

        fmt.Println("Area of child with color ", child.color, " ", child.Area())

    }

}

此示例显然无法编译,因为虽然 Canvas 的 String() 方法可以调用 c.Area(),但它无法访问 c.color,因为无法确保实现 AreaCalculator 的结构具有该属性。


我能想到的一种解决方案是这样做:


type AreaCalculator interface {

  Area() int

  Color() string

}


type Rectangle struct {

    color  string

    width  int

    height int

}


type (r *Rectangle) Color() string {

   return r.color

}


type (r *Rectangle) Area() int {

   return r.width * r.height

}


type Circle struct {

    color    string

    diameter int

}


type (c *Circle) Area() int {

   return r.diameter / 2 * r.diameter / 2 * π

}

type (c *Circle) Color() string {

   return c.color

}


type Canvas struct {

    children []AreaCalculator

}


func (c *Canvas) String() {

    for child := range c.children {

        fmt.Println("Area of child with color ", child.Color(), " ", child.Area())

    }

}


拉莫斯之舞
浏览 85回答 2
2回答

茅侃侃

一个重要的起点是你不应该模仿 Go 中的继承。Go 没有继承。它有接口,也有嵌入。他们没有忘记包括继承;它故意不是语言的一部分。Go 鼓励组合。您的Canvas需求不止一个AreaCalculator。它需要提供颜色的东西。你需要表达出来。例如,您可以这样做:type DrawableShape interface {  AreaCalculator  Color() string}然后你会实现Color()forRectangle和Circle。func (r Rectangle) Color() string {  return r.color}func (c Circle) Color() string {  return c.color}并且children会是[]DrawableShape:children []DrawableShape那会留下这样的东西(建立在 Mohammad Nasirifar 的代码之上)。package mainimport (    "fmt"    "math"    "strings")type AreaCalculator interface {    Area() int}type DrawableShape interface {  AreaCalculator  Color() string}type Rectangle struct {    color  string    width  int    height int}func (r Rectangle) Area() int {    return r.width * r.height}func (r Rectangle) Color() string {  return r.color}type Circle struct {    color    string    diameter int}func (c Circle) Area() int {    area := math.Round(float64(c.diameter*c.diameter) * math.Pi / float64(4))    return int(area)}func (c Circle) Color() string {  return c.color}type Canvas struct {    children []DrawableShape}func (c Canvas) String() string {    lines := make([]string, 0)    for _, child := range c.children {        lines = append(lines, fmt.Sprintf("Area of child with color %s %d", child.Color(), child.Area()))    }    return strings.Join(lines, "\n")}func main() {    circle := &Circle{color: "red", diameter: 2}    rect := &Rectangle{color: "blue", width: 3, height: 4}    canvas := &Canvas{        children: []DrawableShape{circle, rect},    }    fmt.Println(canvas.String())}

汪汪一只猫

这里的关键观察是,如果您需要特定功能,请明确说明。也不要代表他们做其他对象的工作。另请注意,String()必须返回一个字符串,而不是写入stdout.package mainimport (    "fmt"    "math"    "strings")type AreaCalculator interface {    fmt.Stringer    Area() int}type Rectangle struct {    color  string    width  int    height int}func (r *Rectangle) Area() int {    return r.width * r.height}func (r *Rectangle) String() string {    return fmt.Sprintf("I'm a rectangle %d", r.width)}type Circle struct {    color    string    diameter int}func (c *Circle) Area() int {    area := math.Round(float64(c.diameter*c.diameter) * math.Pi / float64(4))    return int(area)}func (c *Circle) String() string {    return fmt.Sprintf("I'm a circle: %d", c.diameter)}type Canvas struct {    children []AreaCalculator}func (c *Canvas) String() string {    lines := make([]string, 0)    for _, child := range c.children {        lines = append(lines, child.String())    }    return strings.Join(lines, "\n")}func main() {    circle := &Circle{color: "red", diameter: 2}    rect := &Rectangle{color: "blue", width: 3, height: 4}    canvas := &Canvas{        children: []AreaCalculator{circle, rect},    }    fmt.Println(canvas.String())}
随时随地看视频慕课网APP

相关分类

Go
我要回答