减少Golang中的代码重复
我很难找到解决代码重复问题的方法。问题出在这里。考虑以下事项:减少Golang中的代码重复,go,interface,refactoring,code-duplication,Go,Interface,Refactoring,Code Duplication,我很难找到解决代码重复问题的方法。问题出在这里。考虑以下事项: type ( WithKey interface { key() string } SharedFunctionality interface { WithKey MethodA() string MethodB() string // ... etc ... } FirstType struct { ... } SecondType struct { ... }
type (
WithKey interface {
key() string
}
SharedFunctionality interface {
WithKey
MethodA() string
MethodB() string
// ... etc ...
}
FirstType struct { ... }
SecondType struct { ... }
// ... etc ...
)
func (ft *FirstType) key() string { ... }
func (st *SecondType) key() string { ... }
func runMethodA(k WithKey) string {
key := k.key()
// do something and return a string
}
func runMethodB(k WithKey) string {
key := k.key()
// do something else and return a string
}
func (ft *FirstType) MethodA() string { return runMethodA(ft) }
func (ft *FirstType) MethodB() string { return runMethodB(ft) }
func (st *SecondType) MethodA() string { return runMethodA(st) }
func (st *SecondType) MethodB() string { return runMethodB(st) }
现在,SharedFunctionality
中的方法只依赖于key()
方法的结果。我可以像下面这样实现它们:
type (
WithKey interface {
key() string
}
SharedFunctionality interface {
WithKey
MethodA() string
MethodB() string
// ... etc ...
}
FirstType struct { ... }
SecondType struct { ... }
// ... etc ...
)
func (ft *FirstType) key() string { ... }
func (st *SecondType) key() string { ... }
func runMethodA(k WithKey) string {
key := k.key()
// do something and return a string
}
func runMethodB(k WithKey) string {
key := k.key()
// do something else and return a string
}
func (ft *FirstType) MethodA() string { return runMethodA(ft) }
func (ft *FirstType) MethodB() string { return runMethodB(ft) }
func (st *SecondType) MethodA() string { return runMethodA(st) }
func (st *SecondType) MethodB() string { return runMethodB(st) }
我不喜欢这种方法的地方在于,当我添加更多类型(ThirdType、FourthType等)或向SharedFunction添加更多方法时,我必须添加大量样板代码。。。具体地说,对于SharedFunctionality中的M个方法和N个类型,我必须像上面的4个一样写出M*N个一行程序
我想做的是:
func (k WithKey) MethodA() string {
key := k.key()
// do something
}
first := ... getFirstTypeValue()
sfs := &SharedFuncStruct{first}
sfs.MethodA() // etc
换句话说:我想在接口类型上定义一个方法。含义:所有实现“WithKey”的对象将自动获得MethodA()字符串
,MethodB()字符串
,等等,因此它们将自动实现共享功能
接口。类似于Java接口中的默认方法
但是,我知道不可能在接口类型中定义方法
解决这个问题的方法是什么
我看到了一种方法,在这种方法中,我将使用接口类型的匿名字段创建一个结构,然后在其中实现方法:
type SharedFuncStruct struct {
WithKey
}
func (sfs *SharedFuncStruct) MethodA() string {
key := sfs.key()
// whatever
}
// same for MethodB()
然后,要使用它,我会做如下操作:
func (k WithKey) MethodA() string {
key := k.key()
// do something
}
first := ... getFirstTypeValue()
sfs := &SharedFuncStruct{first}
sfs.MethodA() // etc
这看起来是可行的,但感觉还是太多的样板代码
还有其他选择吗?在我看来,您需要提取一个包。我使用这个函数的方式是
package keyed
type hasKey interface {
Key() string
}
func MethodA(k hasKey) string {
key := k.Key()
// whatever
}
func MethodB(k hasKey) string {
key := k.Key()
// whatever
}
然后
package your_package
import "keyed"
type (
FirstType struct { ... }
SecondType struct { ... }
)
func (ft *FirstType) Key() string { ... }
func (st *SecondType) Key() string { ... }
func main() {
first := &FirstType{}
second := &SecondType{}
keyed.MethodA(first)
keyed.MethodA(second)
keyed.MethodB(first)
keyed.MethodB(second)
}
有趣的事实:您可以将接口嵌入到结构中,然后结构自动实现该接口。您可以使用它来有效地定义接口上的方法: 在这种情况下,
KeyHolder
struct嵌入了WithKey
接口,因此可以保存任何具有key()字符串
方法的内容(这两种方法都是FirstType
和SecondType
所具有的)。然后可以在该结构上定义MethodA
和MethodB
,然后该结构将使用嵌入的WithKey
返回的任何键来实现WithKey
接口(因为它嵌入了它)和SharedFunction
接口
换句话说,与用key在
中包装FirstType
,然后在SharedFunctionality
中包装FirstType
不同(意思是FirstType
本身必须定义key()
,MethodA()
和MethodB()
),您可以用key
将FirstType
包装在中,然后嵌入它(作为带有按键的界面)在另一个结构中,它仅用于定义默认方法MethodA
和MethodB
,然后实现SharedFunctionality
接口。您已经大致概述了您的选项。请参见下面dave的答案。并思考一下:如果一个具体类型已经有了会发生什么de>MethodA()
method除了key()
?至少嵌入使得MethodA()
的含义(在“最浅的深度”)更加明确。您的问题本质上是“如何在go中实现继承和虚拟方法?”,但我认为你可能有一个xy问题。如果你描述一下你正在做的事情的背景,可能有一个解决方案不是基于java风格的面向对象设计,它更适合go。我喜欢这种方法。我仍然觉得我必须键入比我预期的更多的内容(即,在功能上执行新闻共享)(firstTypeInstance)
因此我可以调用我的.MethodA()
),但这似乎是我能得到的最好的方法。我也喜欢Dave的方法,但至少现在,这个解决方案似乎对我更有效(即,让一个对象实现这些方法,而不必调用包上的函数)。谢谢!谢谢!这肯定会减少样板代码的数量。我当然会考虑为某些场景创建包。对于我目前正在处理的特定场景,Kaedys的建议似乎更好一些——我接受他的解决方案;但也感谢您的解决方案,非常优雅和有用。+1!