Skip to content

berkaroad/ioc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

72 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ioc

Inversion of Control (IoC)

Feature

    1. Support service as singleton and transient
    1. Support resolve service by parent if not found in current
    1. Support inject to function or *struct with services that has registered

    Should add struct tag 'ioc-inject:"true"' to field if want to be injected, but field type ioc.Resolver is not necessary.

    1. Support override exists service

    Register to parent's container, and then register to current's to override parent's.

    1. Support inject to singleton instance automatically

    Inject to singleton instance and it's initialize method Initialize(XXX) or another one which the returns of method InitializeMethodName() string automatically.

    It will use zero value instead of panic if depended service not registerd.

Usage

package main

import (
    "github.com/berkaroad/ioc"
)

type Interface1 interface {
    GetC2Name() string
}

type Interface2 interface {
    GetName() string
}

type Class1 struct {
    Resolver ioc.Resolver
    C2       *Class2 `ioc-inject:"true"`
}

func (c *Class1) GetC2Name() string {
    return c.C2.Name
}

type Class2 struct {
    Name     string
    resolver ioc.Resolver
}

func (c *Class2) GetName() string {
    return c.Name
}

func (c *Class2) Initialize(resolver ioc.Resolver) string {
    c.resolver = resolver
    return c.Name
}

type Interface3 interface {
    GetName() string
}

type Class3 struct {
    Name     string
    resolver ioc.Resolver
}

func (c *Class3) GetName() string {
    return "Class3-" + c.Name
}

// specific custom initialize method name
func (c *Class3) InitializeMethodName() string {
    return "MyInitialize"
}

// custom initialize method
func (c *Class2) MyInitialize(resolver ioc.Resolver) string {
    c.resolver = resolver
    return c.Name
}

type Class4 struct {
    Name     string
}

func (c *Class4) GetName() string {
    return "Class3-" + c.Name
}

func main() {
    // register service to *struct
    ioc.AddSingleton[*Class2](&Class2{Name: "Jerry Bai"})
    ioc.AddTransient[*Class1](func() *Class1 {
        var svc Class1
        // inject to *struct
        ioc.Inject(&svc)
    }

    // register service to interface.
    ioc.AddSingleton[Interface2](&Class2{Name: "Jerry Bai"})
    ioc.AddTransient[Interface1](func() Interface1 {
        var svc Class1
        // inject to *struct
        ioc.Inject(&svc)
    }

    // get service from ioc
    c1 := ioc.GetService[*Class1]
    c2 := ioc.GetService[*Class2]
    i1 := ioc.GetService[Interface1]
    i2 := ioc.GetService[Interface2]

    // inject to function
    ioc.Inject(func(c1 *Class1, c2 *Class2, i1 Interface1, i2 Interface2, resolver ioc.Resolver) {
        println("c1.C2Name=", c1.C2.Name)
        println("c2.Name=", c2.Name)
        println("i1.GetC2Name=()", i1.GetC2Name())
        println("i2.GetName=()", i2.GetName())
    })

    // override exists service
    c := ioc.New()
    ioc.SetParent(c)
    ioc.AddSingletonToC[Interface3](c, &Class3{Name: "Jerry Bai"}) // add service to parent's container
    i3 := ioc.GetService[Interface3]() // *Class3, 'Interface3' only exists in parent's container
    ioc.AddSingleton[Interface3](&Class4{Name: "Jerry Bai"}) // add service to global's container
    i3 = ioc.GetService[Interface3]() // *Class4, 'Interface3' exists in both global and parent's container
}

Benchmark

go test -run=none -count=1 -benchtime=1000000x -benchmem -bench=. ./...

goos: linux
goarch: amd64
pkg: github.com/berkaroad/ioc
cpu: AMD Ryzen 7 5800H with Radeon Graphics         
BenchmarkGetSingletonService-4           1000000                26.16 ns/op            0 B/op          0 allocs/op
BenchmarkGetTransientService-4           1000000               370.9 ns/op            48 B/op          1 allocs/op
BenchmarkGetTransientServiceNative-4     1000000               131.9 ns/op            48 B/op          1 allocs/op
BenchmarkInjectToFunc-4                  1000000               659.5 ns/op           144 B/op          5 allocs/op
BenchmarkInjectToFuncNative-4            1000000                89.26 ns/op            0 B/op          0 allocs/op
BenchmarkInjectToStruct-4                1000000               311.7 ns/op             0 B/op          0 allocs/op
BenchmarkInjectToStructNative-4          1000000                87.64 ns/op            0 B/op          0 allocs/op
PASS
ok      github.com/berkaroad/ioc        1.686s