如何在 Golang 中保持代码干燥
How to keep code DRY in Golang
编辑++:
如何在 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
类型的所有方法来实现接口。但是 Kingdom
和 Phylum
两种类型的方法是相同的。是否有可能只为 Tiger
类型实现 Family
方法:
func (t Tiger) Family() string {return "Felidae"}
而不是为每种类型重复所有三种方法?
免责声明
请不要与方法中的简单字符串 returns 混淆,在实际情况中,我需要不同的方法实现而不仅仅是预定义值。使用这种愚蠢的风格,我想避免玷污你的大脑。所以完全跳过方法不是办法。谢谢
这看起来很像是对接口的滥用。接口不能替代 类;它们表达了一个类型可以做什么。你在这里拥有的是数据。将数据存储在结构中。
type Animal struct {
kingdom string
phylum string
family string
}
var wolf = Animal{"Animalia", "Chordata", "Canidae"}
var tiger = wolf
tiger.family = "Felidae"
这是经典作文:
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())
}
由于我对该功能很感兴趣,所以我阅读了一些有关该主题的文章并将其汇总为几个参考点。
嵌入
名为 "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,但无论如何代码都必须是 DRY。考虑该功能的最清晰方法是将其视为用方法包装结构。因此,描述匿名字段的最真实的方式是 "decorator" 模式(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())
}
这样我们就可以避免为每个类型实现每个必需的方法。
接口
接口也一样。但是,如果多个接口组合在一起,这意味着我们不需要声明已经在使用的接口中声明的方法。
编辑++:
如何在 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
类型的所有方法来实现接口。但是 Kingdom
和 Phylum
两种类型的方法是相同的。是否有可能只为 Tiger
类型实现 Family
方法:
func (t Tiger) Family() string {return "Felidae"}
而不是为每种类型重复所有三种方法?
免责声明
请不要与方法中的简单字符串 returns 混淆,在实际情况中,我需要不同的方法实现而不仅仅是预定义值。使用这种愚蠢的风格,我想避免玷污你的大脑。所以完全跳过方法不是办法。谢谢
这看起来很像是对接口的滥用。接口不能替代 类;它们表达了一个类型可以做什么。你在这里拥有的是数据。将数据存储在结构中。
type Animal struct {
kingdom string
phylum string
family string
}
var wolf = Animal{"Animalia", "Chordata", "Canidae"}
var tiger = wolf
tiger.family = "Felidae"
这是经典作文:
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())
}
由于我对该功能很感兴趣,所以我阅读了一些有关该主题的文章并将其汇总为几个参考点。
嵌入
名为 "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,但无论如何代码都必须是 DRY。考虑该功能的最清晰方法是将其视为用方法包装结构。因此,描述匿名字段的最真实的方式是 "decorator" 模式(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())
}
这样我们就可以避免为每个类型实现每个必需的方法。
接口
接口也一样。但是,如果多个接口组合在一起,这意味着我们不需要声明已经在使用的接口中声明的方法。