zoukankan      html  css  js  c++  java
  • 【玩转Golang】 通过组合嵌入实现代码复用

          应用开发中的一个常见情景,为了避免简单重复,需要在基类中实现共用代码,着同样有助于后期维护。

    如果在以往的支持类继承的语言中,比如c++,Java,c#等,这很简单!可是go不支持继承,只能mixin嵌入,且看下面的代码:

    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("
     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!")
    }

    如果支持继承,很明显应该输出

     Speak with mouth[M0] : "good luck!"
     Speak with mouth[M1] : "good luck!"

    但是在golang中只能输出:

     Speak with mouth[M0] : "good luck!"
     Speak with mouth[M0] : "good luck!"

    StrongMan中调用Say(),此时可以将指针传递到内嵌类,只是简单的指向了Man的方法,在ManKind中调用GetMouth就是ManKind自己的GetMouth,和StrongMan没有关系。

    当然,我们可以在StrongMan中覆盖Say方法

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

    此时,当然可以正确输出,因为本来调用的就都是StrongMan自己的方法了,这又和我们的初衷相违背了。那么这种情况怎么实现呢?我的方法是,让Man再脏一点儿,把需要的东西传递给组合进来的类。

    给Man增加一个属性mouth,增加一个SetMouth方法,修改一下GetMouth方法,StrongMan的GetMouth方法删除掉,再修改一下NewStrongMan方法,最后的代码如下:

    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("
     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!") }

     当然,如果你不愿意用Get、Set方法,也可以直接输出Man的Mouth属性。

    我总结的嵌入式编程要点:

    1,被嵌入的类的方法,只能访问他自己的字段,包装类即时声明了同名字段也没用。

    2,包装类可以覆盖嵌入类的方法,但是嵌入类访问不到,亦然访问自己的方法。只能在包装类中连同调用方法一同实现。

    3,包装类覆盖嵌入类字段后,亦然可以通过嵌入类的类名访问嵌入类的字段。

  • 相关阅读:
    UOJ#310. 【UNR #2】黎明前的巧克力(FWT)
    cf24D. Broken robot(高斯消元)
    loj#2483. 「CEOI2017」Building Bridges(dp cdq 凸包)
    给博客园加一个会动的小人-spig.js
    loj#6033. 「雅礼集训 2017 Day2」棋盘游戏(二分图博弈)
    loj#6032. 「雅礼集训 2017 Day2」水箱(并查集 贪心 扫描线)
    洛谷P4103 [HEOI2014]大工程(虚树 树形dp)
    Oracle DB SQL 性能分析器
    ORA-000845 与 /dev/shm(tempfs)
    ID3DXMesh接口 创建自己的立方体网格
  • 原文地址:https://www.cnblogs.com/dajianshi/p/4191531.html
Copyright © 2011-2022 走看看