如何在Golang中保留代码DRY

时间:2016-10-25 14:03:30

标签: go interface dry go-interface

编辑++:

如何不在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"}

我为Wolf类型实现了三种方法,我需要实现Tiger类型的所有方法来实现接口。但KingdomPhylum方法对于这两种类型都是相同的。是否有可能仅为Family类型实现Tiger方法:

func (t Tiger) Family() string {return "Felidae"}

并且不要为每种类型重复所有三种方法?

声明

请不要混淆方法中的简单字符串返回,在实际情况下,我需要不同的方法实现,而不仅仅是预定义的值。使用这种愚蠢的风格,我想避免玷污你的大脑。所以跳过方法根本不是。谢谢

3 个答案:

答案 0 :(得分:10)

这是经典的作文:

((IO .: Maybe) a)

游乐场:https://play.golang.org/p/Jp22N2IuHL

答案 1 :(得分:3)

这看起来非常像是滥用接口。接口不是类的替代品;它们是一种类型可以做什么的表达。你在这里有数据。将数据存储在结构中。

dispatcher conf

答案 2 :(得分:3)

由于我对这个功能感兴趣,我已经阅读了一些关于该主题的文章,并将其汇总到几个参考点。

嵌入

名为“embedding”的功能。它解决了重复方法实现的问题。基本语法:

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.
}

包装和装饰

是的,没有OOP,但代码必须是干的。考虑这个特性的最清晰的方法是将其作为包装结构的方法。因此,描述匿名字段最真实的方式是“装饰”模式(众所周知的Pythonistas)。

func (a *Speaker) Introduce(){ // But speaker can introduce itself
    fmt.Println(a.Name) // We have direct access to a wrapped struct attributes.
}

组合和覆盖

我们也可以组合在结构上实现的方法

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

通过这种方式,我们可以避免为每种类型实现每个必需的方法。

接口

接口也是如此。但是如果将几个接口组合在一起,则意味着我们不需要声明已在已使用的接口中声明的方法。

Playground

Dennis Suratna's Blog article

Docs