Roman Romadin
26 Oct 2020
β’
2 min read
About me: I am mostly backend developer and looking for new opportunities in Europe/US as Software Engineer / Backend Developer. My Linkedin: https://www.linkedin.com/in/roman-romadin/
How to dynamically inject dependencies into "Service" in Go?
This solution (approach) is based on:
variadic functions
(https://yourbasic.org/golang/variadic-function/) and self-referential functions
(https://www.geeksforgeeks.org/self-referential-structures/).At first glance, this seems a bit confusing, but it's actually a simple solution. This approach can be used to initialize the application as a whole and to load configuration and other services.
Using variadic function
:
type Option func(*accs)
func (f *accs) AddOptions(opts ...Option) {
for _, opt := range opts {
opt(f)
}
}
Using self-referential functions
:
func BindSubscriptions(v subscriptions.Client) Option {
return func(f *accs) {
f.srvSubscriptions = v
}
}
First of all you should create main service. In our snippet it is accounts
:
accs := accounts.New()
Init the second service (it will be property for main service):
srvSubscriptions := subscriptions.New(111)
After that you should bind second service and set properties for first service:
sbs := accounts.BindSubscriptions(srvSubscriptions)
accs.AddOptions(sbs)
And finally we process business logic (process):
accs.Process(222)
As well we can change any properties in second service (accounts or billing in our snippet): set value = 222
And in addition by using variadic functions
we can add one or more properties into first service:
accs.AddOptions(sbs, bl)
or by this way:
accs.AddOptions(sbs)
accs.AddOptions(bl)
Full code:
.
βββ cmd
βΒ Β βββ main.go
βββ pkg
βΒ Β βββ accounts
βΒ Β βΒ Β βββ service.go
βΒ Β βββ billing
βΒ Β βΒ Β βββ service.go
βΒ Β βββ subscriptions
βΒ Β βββ service.go
βββ README.md
package main
import (
"../pkg/billing"
"../pkg/subscriptions"
"../pkg/accounts"
"fmt"
)
func main() {
fmt.Println("Variant_1:")
variant1()
fmt.Println("Variant_2:")
variant2()
fmt.Println("Variant_3:")
variant3()
}
func variant1() {
accs := accounts.New()
srvAccounts := subscriptions.New(111)
sbs := accounts.BindSubscriptions(srvAccounts)
accs.AddOptions(sbs)
accs.Process(222)
}
func variant2() {
accs := accounts.New()
srvAccounts := subscriptions.New(333)
srvBilling := billing.New()
sbs := accounts.BindSubscriptions(srvAccounts)
bl := accounts.BindBilling(srvBilling)
accs.AddOptions(sbs, bl)
accs.Process(444)
}
func variant3() {
accs := accounts.New()
srvAccounts := subscriptions.New(555)
srvBilling := billing.New()
sbs := accounts.BindSubscriptions(srvAccounts)
bl := accounts.BindBilling(srvBilling)
accs.AddOptions(sbs)
accs.AddOptions(bl)
accs.Process(777)
}
Output result:
Variant_1:
a.Prop (before): 111
a.Prop (after): 222
Variant_2:
a.Prop (before): 333
a.Prop (after): 444
Variant_3:
a.Prop (before): 555
a.Prop (after): 777
All sources you can find in my repository: https://github.com/romanitalian/go-service-options
PR's are welcome.
Any questions: https://twitter.com/romanitalian are also welcome!
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!