I have a program where multiple types of modules are used, but all the different types of modules share certain methods. I'm trying to build a generic factory that can be reused for the different types of modules, but I'm missing something like interface inheritance or however that would be called in Go.
This is an example that I tried to simplify as good as possible:
There is a generic factory which uses a generic Module
interface:
package main
var (
modules []Module
)
type Module interface {
RegisterFlagSet()
GetName() (string)
}
type Factory struct {
instances []Module
}
func RegisterModules(modules []Module) {
modules = modules
}
func (f *Factory) registerFlagSets() {
for _,inst := range f.instances {
inst.RegisterFlagSet()
}
}
func (f *Factory) GetInstance(seek string)(Module) {
for _,inst := range f.instances {
if (inst.GetName() == seek) {
return inst
}
}
panic("cannot find module")
}
Then there's a more specific implementation for the module type Timer
. I'm trying to reuse as much of the factory as possible:
package main
import (
"time"
)
var (
timer_modules = []Timer{
// list all the timer modules here
}
)
type Timer interface {
Module
GetTicker() (*time.Ticker)
}
type TimerFactory struct {
Factory
}
func NewTimerFactory() TimerFactory {
tfact := TimerFactory{}
RegisterModules(timer_modules)
return tfact
}
When I try to build that I get this error:
timer_factory.go:25: cannot use timer_modules (type []Timer) as type []Module in argument to RegisterModules
I don't understand why a variable of type []Timer
cannot be used as type []Module
because all the methods of the interface Module
are also in the interface Timer
, so they should be compatible or not? Is there a way to make them compatible?
Change your declaration of Timer
type Timer interface {
Module
GetTicker()(*time.Ticker)
}
https://golang.org/doc/faq#convert_slice_of_interface gives explanations. One of the workarounds is to implement a new register function:
func RegisterModule(m Module) {
modules = append(modules, m)
}
and invoke the function in a range at the cost of only two more lines:
func NewTimerFactory() TimerFactory {
tfact := TimerFactory{}
for _, t := range timer_modules {
RegisterModule(t)
}
return tfact
}