Home > database >  Dependency injection using go interface
Dependency injection using go interface

Time:07-18

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.

  • Related