For those who are missing a Dependency injection similar to what we use in some object oriented languages.
This container introduces a "Constructor" for golang structures, Those constructors will automatically be called and the parameters will be resolved by their type hint recursively.
This container also introduces struct autowire notation.
container := godi.New()
func (t *yourStruct) Construct(param yourInterfaceInterface) {}
It works only with receiver functions, this may change in the future.
The parameter type always have to be an interface, the parameter is what have to be resolved, That can be an interface or a struct.
container.Set("TestInterface", NewTest2())
Where "TestInterface" is your interface name, "NewTest2()" returns an interface or a struct. If a Constructor (exported) method is defined it will be called and the hinted dependencies will be resolved from the map (please see later)
- If it is in defined in your home folder, then use only the interface name
- If it is in a sub folder, provide full path, exampe:
examplemodule-1.mod.ExampleInterface
where your interface defined in folder./examplemodule-1/mod/
- If you initiated your project with a domain. (for example this module)
github.com/olbrichattila/godi
. use the path from your module as well. Example:olbrichattila.godi.internal.test.container.noParamConstructorInterface
Note: Look at the test folder for examples, and see the following example as well:
test := NewTest
_, err := container.Get(test)
if err != nil {
fmt.Println(err)
}
test.DoWhatYouWant()
Note: The container also returns the original (test) struct, but as interface{}. if you use this, please typecast it back. (_) parameter
Add annotation to fields like:
type exampleMultipleImpl struct {
Dependency1 exampleMultipleDepInterface `di:"autowire"`
Dependency2 exampleMultipleDepInterface `di:"autowire"`
Dependency3 exampleMultipleDepInterface `di:"autowire"`
}
The dependencies will be auto wired, if you initiate your struct with the DI container as above:
One way of managing dependencies was already introduced above:
container := godi.New()
container.Set("TestInterface", NewTest2())
dependency, err := container.GetDependency("dependencyInterfaceName2")
container := godi.New()
dependencies := map[string]interface{}{
"dependencyInterfaceName1": NewDependency1(),
"dependencyInterfaceName2": NewDependency1(),
"dependencyInterfaceName3": NewDependency1(),
}
container.Build(dependencies)
container := godi.New()
dependencies := map[string]interface{}{
"dependencyInterfaceName1": NewDependency1(),
"dependencyInterfaceName2": NewDependency1(),
"dependencyInterfaceName3": NewDependency1(),
}
container.Build(dependencies)
result, err := container.Call(TestFunc)
// Where result is a slice of Reflect.Value
func TestFunc(d1 dependencyInterfaceName1, d2 dependencyInterfaceName2, d3 dependencyInterfaceName3) {
}
container := godi.New()
dependencies := map[string]interface{}{
"dependencyInterfaceName1": NewDependency1(),
"dependencyInterfaceName2": NewDependency1(),
"dependencyInterfaceName3": NewDependency1(),
}
container.Build(dependencies)
result, err := container.Call(TestFunc, 55, "Hello")
// Where result is a slice of Reflect.Value
func TestFunc(intValue int, stringValue string, d1 dependencyInterfaceName1, d2 dependencyInterfaceName2, d3 dependencyInterfaceName3) {
}
The above examples are always returning the initiated struct (like a singleton)
If you would like to have a new instance, use a function to create the binding with the function.
The function must follow func() interface{}
always
Example:
func yourFunction() {
container := godi.New()
oneParamConstructorMock := newOneParamConstClass()
container.Set("olbrichattila.godi.internal.test.container.noParamConstructorInterface", callerFunc)
_, err := container.Get(oneParamConstructorMock)
...
}
func callerFunc() interface{} {
return YOur()
}
container.Flush()
container.Delete("dependencyInterfaceName2")
count := container.Count()
fmt.Println(count)
Example usage:
main.go
package main
import (
"fmt"
example1 "godi-test/examplemodule-1/mod"
example2 "godi-test/examplemodule-2"
"github.com/olbrichattila/godi"
)
func main() {
container := godi.New()
container.Set("TestInterface2", NewTest2())
container.Set("examplemodule-1.mod.ExampleInterface", example1.New())
container.Set("examplemodule-2.ExampleInterface", example2.New())
_, err := container.Get(NewTest())
if err != nil {
fmt.Println(err)
}
}
func NewTest() TestInterface {
return &test{}
}
type TestInterface interface {
Construct(TestInterface2, example1.ExampleInterface)
}
type test struct{}
func (*test) Construct(i TestInterface2, ex1 example1.ExampleInterface) {
fmt.Println("Hello from construct")
}
func NewTest2() TestInterface2 {
return &test2{}
}
type TestInterface2 interface {
Construct()
}
type test2 struct{}
func (*test2) Construct() {
fmt.Println("Hello from construct 2")
}
examplemodule-1/mod/example1.go
package example1
import (
"fmt"
example2 "godi-test/examplemodule-2"
)
func New() ExampleInterface {
return &example{}
}
type ExampleInterface interface {
Construct(example2.ExampleInterface)
}
type example struct {
}
func (t *example) Construct(e example2.ExampleInterface) {
fmt.Println("Constructor of example1 package called")
}
examplemodule-2/example2.go
package example2
import (
"fmt"
)
func New() ExampleInterface {
return &example{}
}
type ExampleInterface interface {
Construct()
}
type example struct {
}
func (t *example) Construct() {
fmt.Println("Constructor of example2 package called")
}