Я хочу выбрать реализацию интерфейса во время выполнения, используя предоставленную строку.Я не хочу использовать оператор switch - код должен быть универсальным и работать с любой новой структурой, реализующей интерфейс, без необходимости модификации (открытой / закрытой).
Допустим, у меня есть следующая структура:
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")
}
Затем я хотел бы сделать что-то вроде:
func main() {
// let's pretend it's user input
input := []string{"C", "A", "C"}
for _, className := range input {
// struct := StructFromName(className)
// struct.Foo()
}
}
Для печати:
Calling C
Calling A
Calling C
https://play.golang.org/p/mOW5miz5LdU
К моему разочарованиюgo runtime не ведет реестр структурных имен и, как следствие, StructFromName(className)
недоступен.Я бы тоже не хотел создавать такой реестр самостоятельно.Отказ от ответственности: я пишу в основном на языке Java, и у меня есть привычки ООП, поэтому я ожидал чего-то столь же простого, как
Class<?> clazz = Class.forName(className);
Object object = clazz.newInstance();
Foo foo = (Foo) object;
foo.Foo();
Я попробовал другой подход, с методами вместо интерфейса, и он работает, но он кажется хакерским и неидиоматика:
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
Есть ли лучший способ?