mardi 27 novembre 2018

What is the most idiomatic way to mimic inheritance in Go in this specific case?

I've been thinking alot about this particular problem I'm having an how I'm supposed to solve it the cleanest way.

Imagine an application looking like this:

type AreaCalculator interface {
  Area() int
}

type Rectangle struct {
    AreaCalculator
    color  string
    width  int
    height int
}

type Circle struct {
    AreaCalculator
    color    string
    diameter int
}

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

This example obviously would not compile because while the String() method of Canvas can call c.Area(), it can't access c.color since there's no way to make sure that a struct implementing AreaCalculator has that property.

One solutions I could think of was to do it like this:

type AreaCalculator interface {
  Area() int
  Color() string
}

type Rectangle struct {
    AreaCalculator
    color  string
    width  int
    height int
}

type (r *Rectangle) Color() string {
   return r.color
}

type Circle struct {
    AreaCalculator
    color    string
    diameter int
}

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

The other way would be to try something like this:

type Shape struct {
    Area func() int 
    color string
    diameter int
    width int
    height int
}

func NewCircle() Shape {
    // Shape initialisation to represent a Circle. Setting Area func here
}


func NewRectangle() Shape {
    // Shape initialisation to represent a Rectangle. Setting Area func here
}

type Canvas struct {
    children []Shape
}

func (c *Canvas) String() {
    for child := range c.children {
        fmt.Println("Area of child with color", child.color, " ", child.Area())
    }
}

None of these options seem clean to me. I'm sure there's a way cleaner solution I can't think of.

Aucun commentaire:

Enregistrer un commentaire