Im trying to use some dependency injection via go interface after reading some docs about it.
I’ve two methods which should implement one interface
type Shooter interface {
Spec(ev v1alpha1.Ev) (v1beta1.Shoot, error)
}
type Project struct {
Name string
}
https://github.com/JennyMet/testint/blob/master/internal/infra/common.go#L8
The concrete implementation is here https://github.com/JennyMet/testint/blob/master/internal/infra/azure/azure.go#L13 https://github.com/JennyMet/testint/blob/master/internal/infra/gcp/gcp.go#L13
e.g.
func (n Project) Spec(ev v1alpha1.Ev) (v1beta1.Shoot, error) {
var shoot = v1beta1.Shoot{}
fmt.Println(shoot, ev)
return shoot, nil
}
Now I want to get the specific implementation in package above and I tried the following
https://github.com/JennyMet/testint/blob/master/internal/infra/provider.go#L16
func kind(ev v1alpha1.Ev, namespace string) (v1beta1.Shoot, error) {
var shoot v1beta1.Shoot
var e error
switch ev.Spec.Infrastructure.Type {
case "gcp":
project := gcp.Project{Name: namespace}
shoot, e = project.Spec(ev)
if e != nil {
return v1beta1.Shoot{}, e
}
But it doesn’t works, any ideas how can I do it right?
CodePudding user response:
But it doesn’t works
It is not specified, but I assume that Dependency Injection does not work.
Injection requires at least two different entity types. One is injected and the second on is a target receiving that injection.
In your case, you have only one - Injection implemented in two forms gcp
and azure
.
You need to add a target that contains injected interface:
type Target struct {
Specer Shooter
}
func (t *Target) DoWork() {
// here you can use t.Specer.Spec() without knowing implementation details
}
Now you can create Target
using DI:
func NewTarget(specer Shooter) *Target{
return &Target{
Specer: specer,
}
}
Your code typically decides on all used types and injects them (calling NewTarget()
) very close to application start in Composition Root
Update:
Interface is also can be injected into function. It is also Dependency Injection:
func kind(ev v1alpha1.Ev, namespace string, specer Shooter) (v1beta1.Shoot, error) {
...
shoot, e = specer.Spec(ev)
...
}
That is an alternative to a pattern called Service Locator:
func kind(ev v1alpha1.Ev, namespace string) (v1beta1.Shoot, error) {
...
specer := factory.GetSpecer()
shoot, e = specer.Spec(ev)
...
}
Service Locator often referred as antipattern.