Go: Inheritance and object-oriented programming
Inheritance in traditional object-oriented programming offers three features in one. When a Dog
inherits from an Animal
:
- the
Dog
class reuses code from theAnimal
class, - a variable
x
of typeAnimal
can refer to either aDog
or anAnimal
, x.Eat()
will choose anEat
method based on what type of objectx
refers to.
In object-oriented lingo, these features are known as code reuse, polymorphism and dynamic dispatch.
All of these are available in Go, using separate constructs:
- composition and embedding provide code reuse,
- interfaces take care of polymorphism and dynamic dispatch.
Code reuse: composition
If a Dog
needs some or all of the functionality of an Animal
, simply use composition:
type Animal struct {
// …
}
type Dog struct {
beast Animal
// …
}
This gives you full freedom to use the Animal
part of your Dog
as needed. Yes, it's that simple.
Code reuse: embedding
If the Dog
class inherits the exact behavior of an Animal
, this approach can result in some tedious coding:
type Animal struct {
// …
}
func (a *Animal) Eat() { … }
func (a *Animal) Sleep() { … }
func (a *Animal) Breed() { … }
type Dog struct {
beast Animal
// …
}
func (a *Dog) Eat() { a.beast.Eat() }
func (a *Dog) Sleep() { a.beast.Sleep() }
func (a *Dog) Breed() { a.beast.Breed() }
This code pattern is known as delegation.
Go uses embedding for situations like this. The declaration of the Dog
struct and it's three methods can be reduced to:
type Dog struct {
Animal
// …
}
Polymorphism and dynamic dispatch: interfaces
Further down the road your project might have grown to include more animals. At this point you can introduce polymorphism and dynamic dispatch using interfaces.
If you need to put all your pets to sleep, you can define a Sleeper
interface:
type Sleeper interface {
Sleep()
}
func main() {
pets := []Sleeper{new(Cat), new(Dog)}
for _, x := range pets {
x.Sleep()
}
}
No explicit declaration is required by the Cat
and Dog
types. Any type that provides the methods named in an interface may be treated as an implementation.
When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.James Whitcomb Riley