Golang Interface Design for Multiple Parameter and Return Types
https://softwareengineering.stackexchange.com/questions/406216
-
08-03-2021 - |
Domanda
General question
how can I design an interface that can support both
// v1beta1.Deployment
type Deployment struct {
metav1.TypeMeta
metav1.ObjectMeta
Spec v1beta1.DeploymentSpec
Status v1beta1.DeploymentStat
}
type DeploymentInterface interface {
Create(*v1beta1.Deployment) (*v1beta1.Deployment, error)
Update(*v1beta1.Deployment) (*v1beta1.Deployment, error)
UpdateStatus(*v1beta1.Deployment) (*v1beta1.Deployment, error)
}
// v1.Deployment
type Deployment struct {
metav1.TypeMeta
metav1.ObjectMeta
Spec v1.DeploymentSpec
Status v1.DeploymentStat
}
type DeploymentInterface interface {
Create(*v1.Deployment) (*v1.Deployment, error)
Update(*v1.Deployment) (*v1.Deployment, error)
UpdateStatus(*v1.Deployment) (*v1.Deployment, error)
}
which have different parameter and return types?
Details
The above two interfaces are from kubernetes go-client, they define different versions of the API. Since we have to support both of them for different versions of clusters we are running and I don't want to copy our application code for every version, I want to design an interface that can support different versions of Deployment
.
The current code of our application has a lot of helper functions relying on the specific type, for an example:
func (s *KubeControllerService) deploymentCustomImage(deployment *v1beta1.Deployment, appGitBuildConfig *models.AppGitBuildConfig) *v1beta1.Deployment {
}
And we have hundreds of them. It would be very hard to support a new version by copying each function and impossible to maintain such code.
For what I know, since go's lack of generics, to support two different types the only viable way is to use interface. But i'm facing methods with different types of parameters and return values, I have no idea how to design for this scenario in go.
Soluzione
One way of doing can be like demonstrated as below. Here since I know my types I get the values out using the reflect
package & calculate the area. You can run in on playground. Check out reflect package here
import (
"fmt"
"reflect"
)
type shape interface {
area(interface{}, interface{}) interface{}
}
type rect struct{}
type tri struct{}
func (r rect)area(a,b interface{}) interface{} {
fmt.Println(reflect.ValueOf(r).Type(), reflect.ValueOf(b).Kind())
lenf := reflect.ValueOf(a).Float()
widthf := reflect.ValueOf(b).Float()
return lenf * widthf
}
func (t tri)area(a,b interface{}) interface{} {
l := reflect.ValueOf(a).Int()
h := reflect.ValueOf(b).Int()
return h * l
}
func main() {
r := rect{}
t := tri{}
fmt.Println("Area of rectangle:", r.area(4.5, 4.0))
fmt.Println("Area of triangle:", t.area(4, 4))
}
So for your case the DeploymentInterface
interface would look like
type DeploymentInterface interface {
Create(interface{}) (interface{}, error)
Update(interface{}) (interface{}, error)
UpdateStatus(interface{}) (interface{}, error)
}