为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
拉莫斯之舞 2023-05-15 10:03:06
我一直在想很多关于我遇到的这个特殊问题,我应该如何以最干净的方式解决它。想象一个看起来像这样的应用程序: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())    }}
查看完整描述

2 回答

?
茅侃侃

TA贡献1842条经验 获得超21个赞

一个重要的起点是你不应该模仿 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 main


import (

    "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())

}


查看完整回答
反对 回复 2023-05-15
?
汪汪一只猫

TA贡献1898条经验 获得超8个赞

这里的关键观察是,如果您需要特定功能,请明确说明。也不要代表他们做其他对象的工作。


另请注意,String()必须返回一个字符串,而不是写入stdout.


package main


import (

    "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())

}


查看完整回答
反对 回复 2023-05-15
  • 2 回答
  • 0 关注
  • 84 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信