How to not to repeat my code in Go?
type Animal interface {
Kingdom() string
Phylum() string
Family() string
}
type Wolf struct {}
type Tiger struct {}
func (w Wolf) Kingdom() string {return "Animalia"}
func (w Wolf) Phylum() string {return "Chordata"}
func (w Wolf) Family() string {return "Canidae"}
I implemented a three methods for Wolf
type and I need to implement all the methods for Tiger
type to implement the interface. But Kingdom
and Phylum
methods are the same for both types. Is it somehow possible to implement only Family
method for Tiger
type:
func (t Tiger) Family() string {return "Felidae"}
and not to repeat all the three methods for each type?
Please don't be confused with simple string returns in the methods, in a real case I need different method implementations not just pre-defined values. Using this silly style I want to avoid of defiling your brains. So skip methods at all is not the way. Thanks
This is classical composition:
type Wolf struct {
Animalia
Chordata
Canidae
}
type Tiger struct {
Animalia
Chordata
Felidae
}
type Animalia struct{}
func (Animalia) Kingdom() string { return "Animalia" }
type Chordata struct{}
func (Chordata) Phylum() string { return "Chordata" }
type Canidae struct{}
func (Canidae) Family() string { return "Canidae" }
type Felidae struct{}
func (Felidae) Family() string { return "Felidae" }
func main() {
w := Wolf{}
t := Tiger{}
fmt.Println(w.Kingdom(), w.Phylum(), w.Family())
fmt.Println(t.Kingdom(), t.Phylum(), t.Family())
}
Playground: https://play.golang.org/p/Jp22N2IuHL.
This looks very much like an misuse of interfaces. Interfaces are not a replacement for classes; they're an expression of what a type can do. What you have here is data. Store data in structs.
type Animal struct {
kingdom string
phylum string
family string
}
var wolf = Animal{"Animalia", "Chordata", "Canidae"}
var tiger = wolf
tiger.family = "Felidae"
Since I'm interested in the feature I have read a few articles about the topic and aggregated it to several reference points.
The feature named "embedding". And it solves the issue with repeated methods implementations. Base syntax:
type Person struct {
Name string
}
type Speaker struct { // Speaker is an abstract concept it has no name
*Person // There is a type without field name. It is Anonymous.
}
Yes, there is no OOP but code must be DRY anyway. The clearest way to think about the feature is take this as wrapping structs with methods. So the most veracious way to describe anonymous fields is "decorator" pattern (well known for Pythonistas).
func (a *Speaker) Introduce(){ // But speaker can introduce itself
fmt.Println(a.Name) // We have direct access to a wrapped struct attributes.
}
Also we can combine methods implemented on a structs
func (s Speaker) Speak() string {
return "Blah-blah"
}
type Den struct { // Combine Person and Speaker under Den struct
Person
Speaker
}
func (d Den) Speak() string { // Override Speak method only for Dennis
return "I'm quit!"
}
func main() {
den := Den{Person: Person{Name: "Dennis",}}
mike := Speaker{Person: Person{Name: "Michael",}}
fmt.Println(den.Introduce())
fmt.Println(den.Speak())
fmt.Println(mike.Introduce())
fmt.Println(mike.Speak())
}
In this way we can avoid implementation of each required method for each type.
Same thing with interfaces. But if several interfaces are combined it means just that we don't need to declare methods which already declared in used interfaces.