在下面的简化代码示例中,我们使用供应商的Go库执行了数十种不同的API调用。
供应商库为我们提供了API调用主体的定义:
// body of api call A
type requestBodyA struct {
aa string
bb int32
}
// body of api call B
type requestBodyB struct {
id string
}
以及具有执行我们呼叫的功能:
// fn performs api call A
func callCreateA(body requestBodyA) {
fmt.Println("Value of body is: ", body)
// makes api call using body requestBodyA
}
// fn performs api call B
func callCreateB(body requestBodyB) {
fmt.Println("Value of body is: ", body)
// makes another api call using body requestBodyB
}
我们使用它们来创建自己的CRUD函数,在其中读取配置文件并执行创建/读取/更新/删除调用:
func createA() {
bodyA := requestBodyA{
aa: "asdasfsd",
bb: 15,
}
// api retry loop
for i := 1; i <= 3; i++ {
// do some pre-checks (generic)
callCreateA(bodyA)
// check for errors (generic)
// check if error is recoverable (generic)
// if not return error (generic)
// if yes use the for loop and try the call again in 1,2,3,5,8,13, .. seconds (generic)
}
}
func createB() {
bodyB := requestBodyB{
id: "someUniqueId",
}
for i := 1; i <= 3; i++ {
// do some pre-checks (generic)
callCreateB(bodyB)
// check for errors (generic)
// check if error is recoverable (generic)
// if not return error (generic)
// if yes use the for loop and try the call again in 1,2,3,5,8,13, .. seconds (generic)
}
}
您可以在函数createA
,createB
中看到,我们在创建的每个CRUD中重复很多通用代码(预检查,错误处理,重试循环等等)。由于我们要处理30多个资源,并且每个资源都有自己的创建,读取,更新,销毁API调用函数,因此我们将相同的代码复制了100多次。
我想将所有通用的东西移到某个genericApiCaller(),并将调用主体作为一个参数和名称,或者将指向API调用函数的指针作为第二个参数。
问题1:callCreateA
和callCreateB
需要不同类型的“主体”。如果它们使用interface {}会更容易,但是这些功能来自供应商SDK,并且修改它们并不明智(更新原因等)。如何动态地将genericApiCaller()的“ body interface {}”声明为“ body requestBodyA”或“ body requestBodyB”?在Go中无法进行运行时断言,但是我没有找到任何好的解决方案。
问题2:如何将具有不同类型参数的函数作为参数传递给genericApiCaller()?
您可以尝试扩展供应商类型以使用诸如CallCreate接口之类的东西:
type myBodyA requestBodyA
func (b myBodyA) CallCreate() {
callCreateA((requestBodyA)(b))
}
type myBodyB requestBodyB
func (b myBodyB) CallCreate() {
callCreateB((requestBodyB)(b))
}
type CallCreate interface {
CallCreate()
}
func main() {
var ifs CallCreate
ifs = myBodyA{
aa: "aa",
bb: 15,
}
for i := 1; i <= 3; i++ {
ifs.CallCreate()
}
ifs = myBodyB{
id: "someUniqueId",
}
for i := 1; i <= 3; i++ {
ifs.CallCreate()
}
您也可以使用类似的东西
func genericApiCall(api,body interface{}) {
av := reflect.ValueOf(api)
av.Call([]reflect.Value{reflect.ValueOf(body)})
}
func main() {
bodyA := requestBodyA{
aa: "asdasfsd",
bb: 15,
}
genericApiCall(callCreateA,bodyA)
bodyB := requestBodyB{
id: "someUniqueId",
}
genericApiCall(callCreateB,bodyB)
}
但是,我认为第二个不太优雅。