I’ve not used interfaces in any language before so I’m still trying to get my head around it. I’d appreciate some feedback and elaboration on my current understanding. I may be misunderstanding this completely! I am sometimes thinking this interface abstraction thing may be hiding details that might of been more clear had I called the methods directly. In my code below, the type Shaper interface looks like fluff to me. Anyway, here goes…
A type interface proxies the type and value of variables and their method calls.
A type interface declares a group of related method names and their signatures, such that when assignments are made or methods called, the correct method is used based on the receiver type.
A type interface usually has two or more methods. If only one method is declared then you might as well just call the method directly.
Here is a test program I wrote: This works even though there is no Perimeter method for Dim3 (of course, it is never called).
package main
import (
"fmt"
)
type Shaper interface {
Volume() float64
Perimeter() float64
}
type Dim2 struct {
x float64
y float64
}
type Dim3 struct {
x float64
y float64
z float64
}
func (d Dim2) Volume() float64 {
return d.x * d.y
}
func (d Dim3) Volume() float64 {
return d.x * d.y * d.z
}
func (s Dim2) Perimeter() float64 {
return (s.x + s.y) * 2
}
func print(s Shaper) {
fmt.Println("Shaper Perimeter :", s.Perimeter() )
}
func main() {
a := Dim2{x : 2, y : 4}
b := Dim3{x : 2, y : 4, z : 8}
fmt.Println("Dim2 Volume :", a.Volume() )
fmt.Println("Dim3 Volume :", b.Volume() )
var s Shaper = a
print( s )
}
There are many cases of single-method interfaces, e.g. io.Writer which has a single Write() method. The purpose of an interface is to enable polymorphism or “duck-typing”, where you don’t care what exact type you are getting but you need to make sure it has a certain set of methods. For example, you might be writing some kind of network library but you don’t care if it is a file, a network connection, or a piece of spaghetti, as long as you can write to it. On the other hand, if you know what type you are working with and that it will not be any other type, it is more efficient to call the method directly.
When you think it’s a duck that can swim, then everything that has a swimming behavior is a duck. Interface usage is widespread in golang, which only allows developers to focus on the behavior itself, not the object.
You are using an abstract example that doesn’t solve any problem.
Let me simplify this topic: An interface allows your functions and variables to accept different types. This is the whole reason why interfaces exist.
Imagine you are creating a fantasy game and you want to create a function that calculates the damage of a creature passed as an argument to that function.
Without interfaces, you would have to write a separate function for each creature. Something like this:
func calculateDamage(dragon: Dragon)
func calculateDamage(orc: Orc)
func calculateDamage(troll: Troll)
func calculateDamage(dwarf: Dwarf)
func calculateDamage(elf: Elf)
// and so on for every creature in the game
Instead of that, you can create a common interface called Creature for each NPC in your game and instead write a single function that accepts any struct that implements this interface: