better interface support
This commit is contained in:
parent
24e307bd32
commit
26e6d8261b
69
README.md
69
README.md
@ -15,7 +15,7 @@ import "git.apihub24.de/admin/generic-di"
|
||||
|
||||
func init() {
|
||||
// register the Struct Constructor Function for DI
|
||||
di.Injectable(NewConfiguration)
|
||||
di.Injectable[*Configuration, *Configuration](NewConfiguration)
|
||||
}
|
||||
|
||||
type Configuration struct {
|
||||
@ -40,7 +40,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
di.Injectable(NewGreeter)
|
||||
di.Injectable[*Greeter, *Greeter](NewGreeter)
|
||||
}
|
||||
|
||||
type Greeter struct {
|
||||
@ -67,7 +67,7 @@ package main
|
||||
import "git.apihub24.de/admin/generic-di"
|
||||
|
||||
func init() {
|
||||
di.Injectable(NewMessageService)
|
||||
di.Injectable[*MessageService, *MessageService](NewMessageService)
|
||||
}
|
||||
|
||||
type MessageService struct {
|
||||
@ -94,7 +94,7 @@ package main
|
||||
import di "git.apihub24.de/admin/generic-di"
|
||||
|
||||
func main() {
|
||||
msgService := di.Inject[*MessageService]()
|
||||
msgService := di.Inject[*MessageService, *MessageService]()
|
||||
// prints the message "Hello, Markus"
|
||||
println(msgService.Welcome())
|
||||
}
|
||||
@ -110,7 +110,7 @@ package main
|
||||
import "git.apihub24.de/admin/generic-di"
|
||||
|
||||
func init() {
|
||||
di.Injectable(newMessageService)
|
||||
di.Injectable[IMessageService, *messageService](newMessageService)
|
||||
}
|
||||
|
||||
type IMessageService interface {
|
||||
@ -141,13 +141,13 @@ package main
|
||||
import di "git.apihub24.de/admin/generic-di"
|
||||
|
||||
func main() {
|
||||
msgService := di.Inject[IMessageService]()
|
||||
msgService := di.Inject[IMessageService, *messageService]()
|
||||
// prints the message "Hello, Markus"
|
||||
println(msgService.Welcome())
|
||||
}
|
||||
```
|
||||
|
||||
## Replace Instance
|
||||
## Multiple Instance
|
||||
|
||||
services/message_service.go
|
||||
|
||||
@ -157,27 +157,38 @@ package services
|
||||
import "git.apihub24.de/admin/generic-di"
|
||||
|
||||
func init() {
|
||||
di.Injectable(newMessageService)
|
||||
di.Injectable[IMessageService, *MessageService](newMessageService)
|
||||
di.Injectable[IMessageService, *MessageServiceMock](newMessageServiceMock)
|
||||
}
|
||||
|
||||
type IMessageService interface {
|
||||
Welcome() string
|
||||
}
|
||||
|
||||
type messageService struct {
|
||||
type MessageService struct {
|
||||
greeter *Greeter
|
||||
}
|
||||
|
||||
func NewMessageService() IMessageService {
|
||||
func newMessageService() IMessageService {
|
||||
return &messageService{
|
||||
// here was the Greeter from greeter.go injected
|
||||
greeter: di.Inject[*Greeter](),
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *messageService) Welcome() string {
|
||||
func (ctx *MessageService) Welcome() string {
|
||||
return ctx.greeter.Greet()
|
||||
}
|
||||
|
||||
type MessageServiceMock struct {}
|
||||
|
||||
func newMessageServiceMock() IMessageService {
|
||||
return &MessageServiceMock{}
|
||||
}
|
||||
|
||||
func (svc *MessageServiceMock) Welcome() string {
|
||||
return "Hello, Mock"
|
||||
}
|
||||
```
|
||||
|
||||
main.go
|
||||
@ -188,36 +199,14 @@ package main
|
||||
import di "git.apihub24.de/admin/generic-di"
|
||||
|
||||
func main() {
|
||||
msgService := di.Inject[services.IMessageService]()
|
||||
// get the basic implementation
|
||||
msgService := di.Inject[services.IMessageService, *services.MessageService]()
|
||||
// prints the message "Hello, Markus"
|
||||
println(msgService.Welcome())
|
||||
|
||||
// get the mock implementation
|
||||
msgService = di.Inject[services.IMessageService, *services.MessageServiceMock]()
|
||||
// prints the message "Hello, Mock"
|
||||
println(msgService.Welcome())
|
||||
}
|
||||
```
|
||||
|
||||
message_service_test.go
|
||||
|
||||
```go
|
||||
package services_test
|
||||
|
||||
func init() {
|
||||
// replace the instance of IMessageService with the Mock
|
||||
di.Replace(newMessageServiceMock)
|
||||
}
|
||||
|
||||
type messageServiceMock struct {}
|
||||
|
||||
func newMessageServiceMock() services.IMessageService {
|
||||
return &messageServiceMock{}
|
||||
}
|
||||
|
||||
func (svc *messageServiceMock) Welcome() string {
|
||||
return "Hello, Mock"
|
||||
}
|
||||
|
||||
func TestMessageServiceMocking(t *testing.T) {
|
||||
service := di.Inject[services.IMessageService]()
|
||||
if service.Welcome() != "Hello, Mock" {
|
||||
t.Errorf("expect Hello, Mock but get %s", service.Welcome())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
34
injector.go
34
injector.go
@ -13,18 +13,18 @@ var creators = make(map[string]func() any)
|
||||
var instances = make(map[string]any)
|
||||
|
||||
// Injectable marks a constructor Function of a Struct for DI
|
||||
func Injectable[T any](creator func() T) {
|
||||
func Injectable[T any, K any](creator func() T) {
|
||||
creatorMutex.Lock()
|
||||
defer creatorMutex.Unlock()
|
||||
creators[getSelector[T]()] = func() any {
|
||||
creators[getSelector[T, K]()] = func() any {
|
||||
return creator()
|
||||
}
|
||||
}
|
||||
|
||||
func Replace[T any](creator func() T, identifier ...string) {
|
||||
Injectable(creator)
|
||||
selector := getSelector[T]()
|
||||
instanceSelector := getSelector[T](identifier...)
|
||||
func Replace[T any, K any](creator func() T, identifier ...string) {
|
||||
Injectable[T, K](creator)
|
||||
selector := getSelector[T, K]()
|
||||
instanceSelector := getSelector[T, K](identifier...)
|
||||
cre, creatorExists := creators[selector]
|
||||
if !creatorExists {
|
||||
return
|
||||
@ -38,10 +38,10 @@ func Replace[T any](creator func() T, identifier ...string) {
|
||||
}
|
||||
|
||||
// Inject gets or create a Instance of the Struct used the Injectable constructor Function
|
||||
func Inject[T any](identifier ...string) T {
|
||||
func Inject[T any, K any](identifier ...string) T {
|
||||
var nilResult T
|
||||
selector := getSelector[T]()
|
||||
instanceSelector := getSelector[T](identifier...)
|
||||
selector := getSelector[T, K]()
|
||||
instanceSelector := getSelector[T, K](identifier...)
|
||||
_, instanceExists := instances[instanceSelector].(T)
|
||||
if !instanceExists {
|
||||
creator, creatorExists := creators[selector]
|
||||
@ -62,14 +62,21 @@ func Inject[T any](identifier ...string) T {
|
||||
return instances[instanceSelector].(T)
|
||||
}
|
||||
|
||||
func Destroy[T any](identifier ...string) {
|
||||
func Destroy[T any, K any](identifier ...string) {
|
||||
instanceMutex.Lock()
|
||||
defer instanceMutex.Unlock()
|
||||
instanceSelector := getSelector[T](identifier...)
|
||||
instanceSelector := getSelector[T, K](identifier...)
|
||||
delete(instances, instanceSelector)
|
||||
}
|
||||
|
||||
func getSelector[T any](identifier ...string) string {
|
||||
func getSelector[T any, K any](identifier ...string) string {
|
||||
tName := getTypeName[T]()
|
||||
kName := getTypeName[K]()
|
||||
additionalKey := strings.Join(identifier, "_")
|
||||
return fmt.Sprintf("%s_%s_%s", tName, kName, additionalKey)
|
||||
}
|
||||
|
||||
func getTypeName[T any]() string {
|
||||
var def T
|
||||
typeName := ""
|
||||
typeOf := reflect.TypeOf(def)
|
||||
@ -78,6 +85,5 @@ func getSelector[T any](identifier ...string) string {
|
||||
} else {
|
||||
typeName = reflect.TypeOf((*T)(nil)).Elem().String()
|
||||
}
|
||||
additionalKey := strings.Join(identifier, "_")
|
||||
return fmt.Sprintf("%s_%s", typeName, additionalKey)
|
||||
return typeName
|
||||
}
|
||||
|
||||
@ -9,11 +9,12 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
di.Injectable(newTextService)
|
||||
di.Injectable(newMessageService)
|
||||
di.Injectable(newConfiguration)
|
||||
di.Injectable(newGreetingService)
|
||||
di.Injectable(newBasicOverridableService)
|
||||
di.Injectable[*textService, *textService](newTextService)
|
||||
di.Injectable[*messageService, *messageService](newMessageService)
|
||||
di.Injectable[*configuration, *configuration](newConfiguration)
|
||||
di.Injectable[greetingService, *textService](newGreetingService)
|
||||
di.Injectable[overridableService, *basicOverridableService](newBasicOverridableService)
|
||||
di.Injectable[overridableService, *basicOverridableServiceMock](newBasicOverridableServiceMock)
|
||||
}
|
||||
|
||||
type (
|
||||
@ -64,7 +65,7 @@ func newConfiguration() *configuration {
|
||||
|
||||
func newTextService() *textService {
|
||||
return &textService{
|
||||
config: di.Inject[*configuration](),
|
||||
config: di.Inject[*configuration, *configuration](),
|
||||
id: uuid.NewString(),
|
||||
}
|
||||
}
|
||||
@ -75,7 +76,7 @@ func newGreetingService() greetingService {
|
||||
|
||||
func newMessageService() *messageService {
|
||||
return &messageService{
|
||||
texts: di.Inject[*textService](),
|
||||
texts: di.Inject[*textService, *textService](),
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,29 +143,29 @@ func TestInject_Duplicate(t *testing.T) {
|
||||
func TestInject_Parallel(t *testing.T) {
|
||||
for i := 0; i < 20; i++ {
|
||||
go func() {
|
||||
println(di.Inject[*textService]().GetID())
|
||||
println(di.Inject[*textService, *textService]().GetID())
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func TestInject_MultipleInstances(t *testing.T) {
|
||||
textServiceA := di.Inject[*textService]("a")
|
||||
textServiceB := di.Inject[*textService]("b")
|
||||
textServiceA := di.Inject[*textService, *textService]("a")
|
||||
textServiceB := di.Inject[*textService, *textService]("b")
|
||||
if textServiceA.GetID() == textServiceB.GetID() {
|
||||
t.Errorf("expect a seperate instance textServiceA and textServiceB but there was identical")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTryInterface(t *testing.T) {
|
||||
greeter := di.Inject[greetingService]()
|
||||
greeter := di.Inject[greetingService, *textService]()
|
||||
if greeter.Greeting() != "Hello Markus" {
|
||||
t.Errorf("expect greeting Hello Markus")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTryInterface_MultipleInstances(t *testing.T) {
|
||||
greeterA := di.Inject[greetingService]("a")
|
||||
greeterB := di.Inject[greetingService]("b")
|
||||
greeterA := di.Inject[greetingService, *textService]("a")
|
||||
greeterB := di.Inject[greetingService, *textService]("b")
|
||||
if greeterA.Greeting() != "Hello Markus" {
|
||||
t.Errorf("expect greeting Hello Markus")
|
||||
}
|
||||
@ -177,13 +178,12 @@ func TestTryInterface_MultipleInstances(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOverwriteInjectable(t *testing.T) {
|
||||
basic := di.Inject[overridableService]()
|
||||
basic := di.Inject[overridableService, *basicOverridableService]()
|
||||
basicID := basic.GetInstanceID()
|
||||
if basic.GetValue() != "i am original" {
|
||||
t.Errorf("wrong service instance get")
|
||||
}
|
||||
di.Replace(newBasicOverridableServiceMock)
|
||||
basic = di.Inject[overridableService]()
|
||||
basic = di.Inject[overridableService, *basicOverridableServiceMock]()
|
||||
if basic.GetInstanceID() == basicID {
|
||||
t.Errorf("basic and newOne are the same instance")
|
||||
}
|
||||
@ -193,6 +193,6 @@ func TestOverwriteInjectable(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDestroy(t *testing.T) {
|
||||
_ = di.Inject[textService]("a")
|
||||
di.Destroy[textService]("a")
|
||||
_ = di.Inject[*textService, *textService]("a")
|
||||
di.Destroy[*textService, *textService]("a")
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user