Golang interfaces are nested to realize the operation of reuse

Time:2021-11-8

Let’s look at the code directly~


package main
import (
    "fmt"
)
func main() {
    start(NewB(C{}))
    start(NewB(D{}))
}
type A interface {
    what()
}
type B struct {
    A
}
type C struct {
}
func (b C) what() {
    fmt.Println("this is type C")
}
type D struct {
}
func (b D) what() {
    fmt.Println("this is type D")
}
func start(b B) {
    b.what()
}
func NewB(a A) B {
    return B{a}
}

Supplement: [play with golang] realize code reuse through combination and embedding

A common scenario in application development. In order to avoid simple repetition, common code needs to be implemented in the base class, which is also helpful for later maintenance.

If in the previous languages that support class inheritance, such as C + +, Java, c# etc., this is very simple! However, go does not support inheritance and can only be embedded in mixin

Let’s look at the following code:


type ManKind interface{
    Say(s string);   
    GetMouth()string
}
type Man struct{
   
}
func NewMan() ManKind{
    return &Man{};
}
func (this *Man)GetMouth()string{
    return "M0"
}
func (this *Man) Say(s string){
    fmt.Printf("\n Speak with mouth[%s] : \"%s\"",this.GetMouth(),s);
}
type StrongMan struct{
    Man
}
func NewStrongMan()ManKind{
    return &StrongMan{}
}
func (this*StrongMan)GetMouth()string{
    return "M1"
}
func main(){    
    NewMan().Say("good luck!")
    NewStrongMan().Say("good luck!")
}

If inheritance is supported, it should obviously be output

Speak with mouth[M0] : “good luck!”

Speak with mouth[M1] : “good luck!”

However, in golang, you can only output:

Speak with mouth[M0] : “good luck!”

Speak with mouth[M0] : “good luck!”

In StrongMan, calling Say (), at this time, you can pass pointer to the embedded class, it is just a way of pointing to Man. Calling GetMouth in ManKind is ManKind’s own GetMouth, and it doesn’t matter with StrongMan.

Of course, we can override the say method in strongman


func (this *StrongMan)Say(s string){
    fmt.Printf("\n Speak with mouth[%s] : \"%s\"",this.GetMouth(),s);
}

At this time, of course, it can be output correctly, because all the methods called are strongman’s own methods, which is contrary to our original intention. So how does this happen? My method is to make man a little dirty and pass what I need to the combined classes.

Add an attribute mouth to man, add a setmouth method, modify the getmouth method, delete the getmouth method of strongman, and then modify the newstrongman method

The final code is as follows:


package main
import(
    "fmt"
)
type ManKind interface{
    Say(s string);    
    SetMouth(m string)
    GetMouth()string
}
type Man struct{
    ManKind    
    mouth string
}
func NewMan() ManKind{
    return &Man{mouth:"M0"};
}
func (this *Man)GetMouth()string{
    return this.mouth;
}
func (this *Man)SetMouth(s string){
    this.mouth=s;
}
func (this *Man) Say(s string){
    fmt.Printf("\n Speak with mouth[%s] : \"%s\"",this.GetMouth(),s);
}
type StrongMan struct{
    Man
}
func NewStrongMan()ManKind{
    sm := &StrongMan{}
  sm.SetMouth("M1");
  return sm;
}
    
func main(){    
    NewMan().Say("good luck!")
    &NewStrongMan().Say("good luck!")
}

Of course, if you don’t want to use get and set methods, you can also directly output man’s mouth attribute.

Key points of embedded programming I summarized:

1. The method of the embedded class can only access its own field. It is useless for the wrapper class to declare the field with the same name immediately.

2. The wrapper class can override the methods of the embedded class, but the embedded class cannot access its own methods. Can only be implemented in a wrapper class with a calling method.

3. After the wrapper class overwrites the embedded class field, the same is true. You can access the embedded class field through the class name of the embedded class.

The above is my personal experience. I hope I can give you a reference, and I hope you can support developpaer. If you have any mistakes or don’t consider completely, please don’t hesitate to comment.