I want to select implementation of an interface at runtime, using provided string. I don't want to use switch statement - the code should be generic and work with any new struct implementing the interface without need to modification (open/closed).
Let's say I have following structure:
type Fooer interface {
Foo()
}
type A struct{}
func (_ *A) Foo() {
fmt.Println("Calling A")
}
type B struct{}
func (_ *B) Foo() {
fmt.Println("Calling B")
}
type C struct{}
func (_ *C) Foo() {
fmt.Println("Calling C")
}
Then, I'd like to do something like:
func main() {
// let's pretend it's user input
input := []string{"C", "A", "C"}
for _, className := range input {
// struct := StructFromName(className)
// struct.Foo()
}
}
To print:
Calling C
Calling A
Calling C
https://play.golang.org/p/mOW5miz5LdU
To my disappointment, go runtime keeps no registry of struct names and as a result, no StructFromName(className)
is available. I wouldn't like to create such registry by my own as well.
Disclaimer: I write mainly in java and I have OOP habits, so I expected something as easy as
Class<?> clazz = Class.forName(className);
Object object = clazz.newInstance();
Foo foo = (Foo) object;
foo.Foo();
I tried another approach, with methods instead of interface, and it works but it feels hacky and non-idiomatic:
type Hack struct{}
func (_ *Hack) FooA() {
fmt.Println("Calling A")
}
func (_ *Hack) FooB() {
fmt.Println("Calling B")
}
func (_ *Hack) FooC() {
fmt.Println("Calling C")
}
func main() {
hack := &Hack{}
// let's pretend it's user input
input := []string{"FooC", "FooA", "FooC"}
for _, funcName := range input {
reflect.ValueOf(hack).MethodByName(funcName).Call(nil)
}
}
https://play.golang.org/p/3ueEuVV2Hx9
Is there a better way?