【问题标题】:Avoid duplicating code between "subtypes"避免在“子类型”之间重复代码
【发布时间】:2019-11-07 22:21:34
【问题描述】:

我正在将一个旧的 Java 项目重写为 Go。

我已经在工作中完成了一些 Go,但我不知道如何将我的 OOP(使用抽象类等)转换为 Go 哲学。

在这个想法中,我有两种类型(即将推出 3 种),它们具有一些通用方法,但其他一些(最多只有 1 或 2 个)应该具有相同的签名但不同的主体。

我知道 Go 没有某种继承。现在我有这样的东西:

type A struct {...}
func (a *A) M1 (){ stuff1 }
func (a *A) M2 (){ stuff2 }
func (a *A) SM (){ special stuff A }

然后:

type B struct {...}
func (b *B) M1 (){ stuff1 }
func (b *B) M2 (){ stuff2 }
func (b *B) SM (){ special stuff B }

我不知道 Go 是如何管理这个的。在 Java 中,我做了一个抽象类,然后用我的两个具体类来实现它。

我想要的是不必复制 M1() 和 M2(),而是能够有一个泛型类型来调用这些方法,然后只需为这两种类型定义 SM()。

【问题讨论】:

    标签: go interface


    【解决方案1】:

    你可以嵌入一个结构体,比如:

    type Common struct {}
    
    func (c *Common) M1() {
        fmt.Println("M1")
    }
    
    func (c *Common) M2() {
        fmt.Println("M2")
    }
    
    type A struct {
        Common
    }
    
    func (a *A) SM() {
        fmt.Println("A SM()")
    }
    
    type B struct {
        Common
    }
    
    func (b *B) SM() {
        fmt.Println("B SM()")
    }   
    
    type Thing interface {
        M1()
        M2()
        SM()
    }
    func main() {
        var a Thing = &A{}
        var b Thing = &B{}
    
        a.M1()
        b.M2()
        a.SM()
        b.SM()
    }
    

    https://play.golang.org/p/Q3mIH_W8X44

    【讨论】:

      【解决方案2】:

      有几种不同的方法可以解决这个问题 - 嵌入并不是唯一的答案。如果这些方法想要访问它们在伪代码中定义的类型的数据(例如,A.M1 需要访问 A 的字段),那么嵌入对您没有帮助,因为嵌入类型不知道该类型它被嵌入其中。你需要从整体上重新考虑你的设计,并将其作为一个 Go 程序,而不是把它设计成一个 Java 程序并试图让这些概念在 Go 中工作。正如许多人所发现的那样,在 Go 中尝试 OOP 设计往往会产生很大的挫败感,而且收效甚微。

      另一方面,如果这些方法不需要访问任何字段,那么为什么它们是方法?这些可能只是纯函数,这将使它们更易于使用和推理,并且将完全消除嵌入或伪造继承的任何顾虑。

      【讨论】: