I'm having trouble find the "go-way" to solve a code duplication issue. Here's the problem. Consider the following:
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 { ... }
Now, the methods in SharedFunctionality
they only depend on the results of the key()
method. I could implement them like the following:
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) }
What I dislike about this approach is that, as I add more types (ThirdType, FourthType, etc) or as I add more methods to SharedFunctionality, I have to add tons of boilerplate code... specifically, for M methods in SharedFunctionality, and N types, I would have to spell out M*N one-liners like the 4 above.
What I would love to do is something like:
func (k WithKey) MethodA() string {
key := k.key()
// do something
}
In other words: I'd love to define a method on an Interface type. Meaning: all objects that implement "WithKey" would automatically get MethodA() string
, MethodB() string
, etc, therefore they would automatically implement the SharedFunctionality
interface. Something like default methods in Java interfaces.
However, I know it's impossible to define a method in an Interface type...
What's the go-way of solving this problem?
I've seen an approach where I would create a struct with an anonymous field of the interface type, and then implement the methods there:
type SharedFuncStruct struct {
WithKey
}
func (sfs *SharedFuncStruct) MethodA() string {
key := sfs.key()
// whatever
}
// same for MethodB()
Then to use it, I would do something like:
first := ... getFirstTypeValue()
sfs := &SharedFuncStruct{first}
sfs.MethodA() // etc
This looks like it could work, but it still feels like too much boilerplate code.
Any other alternatives?