generic-di/container.go

92 lines
2.0 KiB
Go

package di
import (
"fmt"
"reflect"
"strings"
"sync"
)
type container struct {
mu sync.RWMutex
creators map[string]func() any
instances map[string]any
}
var globalContainer *container
var once sync.Once
func getContainer() *container {
once.Do(func() {
globalContainer = &container{
mu: sync.RWMutex{},
creators: make(map[string]func() any),
instances: make(map[string]any),
}
})
return globalContainer
}
func (c *container) injectable(typ reflect.Type, creator func() any) {
c.mu.Lock()
defer c.mu.Unlock()
selector := c.getSelector(typ)
c.creators[selector] = creator
}
func (c *container) replace(typ reflect.Type, creator func() any, identifier ...string) {
c.mu.Lock()
defer c.mu.Unlock()
selector := c.getSelector(typ)
instanceSelector := c.getSelector(typ, identifier...)
c.creators[selector] = creator
createdInstance := creator()
c.instances[instanceSelector] = createdInstance
}
func (c *container) inject(typ reflect.Type, identifier ...string) (any, bool) {
instanceSelector := c.getSelector(typ, identifier...)
c.mu.RLock()
if instance, ok := c.instances[instanceSelector]; ok {
c.mu.RUnlock()
return instance, true
}
c.mu.RUnlock()
c.mu.RLock()
if instance, ok := c.instances[instanceSelector]; ok {
c.mu.RUnlock()
return instance, true
}
c.mu.RUnlock()
selector := c.getSelector(typ)
creator, creatorExists := c.creators[selector]
if !creatorExists {
return nil, false
}
createdInstance := creator()
c.mu.Lock()
c.instances[instanceSelector] = createdInstance
c.mu.Unlock()
return createdInstance, true
}
func (c *container) destroy(typ reflect.Type, identifier ...string) {
c.mu.Lock()
defer c.mu.Unlock()
instanceSelector := c.getSelector(typ, identifier...)
delete(c.instances, instanceSelector)
}
func (c *container) getSelector(typ reflect.Type, identifier ...string) string {
typeName := typ.String()
additionalKey := strings.Join(identifier, "_")
return fmt.Sprintf("%s_%s", typeName, additionalKey)
}