Plymorphism in Go using interface

Learning Go Interface for Polymorphism

What is Polymorphism

Understanding the concept of “Polymorphism” is like “doing something, but the way it is done varies” Like, various “shapes” can “calculate area,” but the methods behind them differ, and in Go, the interface is a collection of methods defined for types.

Having polymorphism allows the program open to extension but closed for modification.

// Before
func getArea() {
if t == "circle" {
// Calculate area of circle
} else if t == "rectangle" {
// Calculate area of rectangle
}
}
// After
type geometry interface {
area() float64
}

Go and Polymorphism

In the following example, Go interface implicitly creates an interface, as long as a type has the required method set for the interface, it “automatically” satisfies that interface.

// 1. Circle and Rectangle
type rect struct {
width, height float64
}
type circle struct {
radius float64
}
// 2. Define the contract of "shape" with the necessary method (calculate area)
type geometry interface {
area() float64
}
// 3. The measurement method must receive a "shape"
func measure(g geometry) {
fmt.Println(g.area())
}
// 4. Implement the area calculation methods for Rectangle and Circle
func (r rect) area() float64 {
return r.width * r.height
}
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func main() {
r := rect{width: 3, height: 4}
c := circle{radius: 5}
measure(r)
measure(c)
}

Interface Composition

Composition can also be achieved through nested interfaces.

package main
import (
"fmt"
"math"
)
// 1. Define Rectangle and Circle
type rect struct {
width, height float64
}
type circle struct {
radius float64
}
// 2. Define single responsibility interfaces
type areaCalculator interface {
area() float64
}
type perimeterCalculator interface {
perimeter() float64
}
// 3. Use interface composition to create a larger interface
type geometry interface {
areaCalculator
perimeterCalculator
}
// 4. Implement for Rectangle and Circle
func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perimeter() float64 {
return 2 * (r.width + r.height)
}
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c circle) perimeter() float64 {
return 2 * math.Pi * c.radius
}
// 5. input composite interface
func measure(g geometry) {
fmt.Printf("Area: %.2f, Perimeter: %.2f\n", g.area(), g.perimeter())
}
func main() {
r := rect{width: 3, height: 4}
c := circle{radius: 5}
measure(r)
measure(c)
}

Further Reading