We all know dependency injection makes packages decoupled.
But I'm a little confused about best practices of dependency injection in go.
Lets assume package User needs to access Config package.
We can pass a Config object to User methods. In this way I can change the Config package functionality as long as the new code resolves the interfaces.
Another approach is call Config package methods directly , In these scenario I can change Config code too as long as the methods names remains the same. Like so
Update :
What is different between these two approaches :
package User
func foo(config ConfigObject) {
config.Foo()
}
And this one :
package User
import Config
func foo() {
config.Foo()
}
Calling config.Foo on the config argument to a method means that you receive an instance of some structure (possibly implementing interface Config) and call the method Foo on that instance/interface. Think of this as of calling a method of an object in OO terms:
package user
func foo(cfg config.Config) {
cfg.Foo()
}
Calling config.Foo having imported the config package means you are calling the function Foo of package config, not of any object/struct/interface. Think of this as pure procedural programming without any objects:
package user
import config
func foo() {
config.Foo()
}
The latter has nothing to do with dependency injection, the former may constitute a part of it if Config is an interface.
Dependency injection, on the other hand, follows generally the same rules in Go as in other languages:
accept interfaces, supply implementations
Because in Go structs satisfy interfaces implicitly rather than explicitly (as it is the case in Java)
the code accepting the value only needs to know about the interface and import it;
the code implementing it does not even need to know about the interface (it can just happen that it satisfies it);
the code that supplies the impl into a method accepting an
interface, obviously, needs to know both.
For your example this means:
package config
type Config interface {
Foo() string
}
package foo
type Foo struct{}
func (f *Foo) Foo() string {
return "foo"
}
package boo
type Boo struct{}
func (b *Boo) Foo() string {
return "boo"
}
package main
func foo(cfg config.Config) string{
return cfg.Foo()
}
func main() {
// here you inject an instance of Foo into foo(Config)
log.Print(foo(&foo.Foo{}))
// here you inject an instance of Boo into foo(Config)
log.Print(foo(&boo.Boo{})
}
Prints
2018/03/03 13:32:12 foo
2018/03/03 13:32:12 boo
Since, in my opinion, the example code given by previous poster(s) could be a bit less confusing for beginners, just by renaming things, i quickly try to do this here:
package contracts
type IConfig interface {
GetSomeString() string
}
package pkg1
type Foo struct{}
func (f *Foo) GetSomeString() string {
return "hello“
}
package pkg2
type Boo struct{}
func (b *Boo) GetSomeString() string {
return "world"
}
package main
func run(config contracts.IConfig) string {
s := config.GetSomeString()
return s
}
func main() {
foo := &pkg1.Foo{}
result1 := run(foo)
log.Print(result1)
boo := &pkg2.Boo{}
result2 := run(boo)
log.Print(result2)
// Prints: helloworld
// You learned:
// Since the run() func use a IConfig interface as
// parameter, the run() func can handle both struct
// types (Foo and Boo) as input, because both struct
// types (Foo and Boo) implement the IConfig interface.
}
Related
I would like to create a library that exports a function that defines its own dependencies without consuming types from an external package (excluding std lib).
The issue is, if my dependency is an interface type with a method that returns a struct, consumers have to use the exact struct declared in the interface.
In situations where I have two or more libraries, each sharing the same interface signature however each package defining its own interface (interface segregation), they conflict when it comes to methods that return struct types.
package mylibrary
type Result struct {
Value string
}
type IFoo interface {
Foo() Result
}
func DoFoo(f IFoo) {
f.Foo()
}
With the above code, anyone implementing this library must use the mylibrary.Result struct exactly to satisfy the IFoo interface.
In the case where I have multiple packages defining the interfaces of their own dependencies, this can become difficult and or impossible
See the following example: https://replit.com/#davidalsh/UsedCarefreeBrain#main.go
// main.go
// Creating an object that satisfies the contract roughly
import (
packagea "main/package-a"
packageb "main/package-b"
)
type Result struct {
Message string
}
type Foo struct {}
// Even though Result is the same shape, this needs to
// return either packagea.Result or packageb.Result
func (*Foo) Foo() Result {
return Result{}
}
func main() {
dep := Foo{}
packagea.DoFoo(dep) // Foo does not implement packagea.IFoo
packageb.DoFoo(dep) // Foo does not implement packageb.IFoo
}
This seems like a strange limitation. Methods on an interface can return types like string, int, []int, etc but not a struct.
Should I be returning an interface with getters/setters from IFoo.Foo, e.g.?
type IResult interface {
Message() string
}
type IFoo interface {
Foo() IResult
}
What if I would like to use a struct as an argument for a function? Should I also only accept an interface of getters?
interface IUserDetails {
FirstName() string
LastName() string
Age() int
}
func SayHello(user IUserDetails) {
fmt.Println("Hello", user.FirstName())
}
Or is there a better way?
Define a type in a third package:
common/common.go
package common
type Result struct {
Message string
}
Use this package in all other packages:
main.go
package main
import (
"main/common"
packagea "main/package-a"
packageb "main/package-b"
)
type Foo struct{}
func (*Foo) Foo() common.Result {
return common.Result{}
}
func main() {
dep := &Foo{}
packagea.DoFoo(dep)
packageb.DoFoo(dep)
}
package-a/packagea.go
package packagea
import "main/common"
type IFoo interface {
Foo() common.Result
}
func DoFoo(f IFoo) {
f.Foo()
}
Run the program on the Go Lang Playground
So i have this import cycle to solve, and my project structure basically likes this:
model.go -> procedure.go -> function.go
In my function i need model and i use interface to handle it. Currently my code basically like this:
type imodel interface {
foo()
}
type model struct {
}
func (m *model) run() {
proc := &procedure{}
proc.run(m)
}
func (m *model) foo() {
//bla bla
}
type procedure struct {
}
func (p *procedure) run(model imodel) {
funct := &function{}
funct.run(model)
}
type function struct {
}
func (f *function) run(model imodel) {
model.foo()
}
My question is should i pass my model using interface thorough every class like that or there's any other workaround?
I would put all of these in the same package. Depending on circumstances, I may put them in different files in the same package.
Also, you do not seem to export imodel, so it would be package-internal and unless you have multiple concrete implementations, you do not need an interface. Then, "imodel" is a less than ideal name, the interface should be named model and each concrete type implementing the interface should be named after what it models.
I have a question regarding dependency injection.
Please consider the example below.
For example, selector() is a function that select something and guarantee return an interface
In this example
bar.node.go
type NodeTemplate struct {
Name string
}
// satisfy interface declared in db.foo.go
//but never imports anything from db.foo.go
func (node *NodeTemplate) GetUuidName() string {
if node != nil {
return node.Name
}
return
}
db.foo.go
// interface declared in db.foo.go
type Node interface {
GetUuidName() string
}
Option A
// So selector receives a map of Some interface and populate a map
func SelectSomething(nodemap map[string]Node, selectFactor string) {
// selection from db and result populate in a map
}
Option B
Another pattern SelectSomething return a Node
and it Interface
So another package will depend on importing Node
and that will introduce a dependency.
func SelectSomething(seleconsomething) []*Node {
// do selection and return a slice of SomeInterface
n := &Node{} // here it need to be concret type T
return Node
}
So based on logic I've described I see the first approach is better but in that approach, select need do concrete type allocation in order to populate a map.
Consider another example
db.foo.go
type Node interface {
GetUuidName() string
}
func inserter(node *Node) error {
// do some work
node.GetUuidName()
}
For a case like in inserter case, inserter has no external dependency, inserter just needs to receive something that satisfies the interface. Declare interfaces locally and that brake a dependancy.
But in the case of selector example, it has to do memory allocation in order to return or populate a map or return something that has concrete type T. So in both case, it has to have internal re-presentation.
So here is my question can selector somehow at run time figure out a type it receives based on the interface and instantiate an object of that type and insert to a map as an interface or return a slice of the interface. ?
By doing so selector function will have no dependancy on what it receives it just guarantee it will instantiate the same object type T
and return interface.
or can selector return interface but I guess I have to have a bi-directional interface between db package and package X or dynamic dispatcher need to do some magic ?
You want a type to behave in a certain way. That is achieved via an interface. This case is no different. Simply add the desired behavior to your interface, as demonstrated below with the Foo interface.
package main
import (
"fmt"
"reflect"
)
type Foo interface {
Bar()
TypeOf() reflect.Type
}
type Baz struct{}
func (b Baz) Bar() {
fmt.Println("I am a Fooer!")
}
func (b Baz) TypeOf() reflect.Type {
return reflect.TypeOf(b)
}
func DoSomeThing(f Foo) {
f.Bar()
fmt.Println(f.TypeOf())
}
func main() {
fmt.Println("Hello, playground")
b := Baz{}
DoSomeThing(b)
}
Run on playground
Suppose I have an interface Foo, and I am adding a struct which needs methods of Foo and few additional methods also. In that case out of following two, which is considered to be best practice? Or if there is some other more appropriate third way, then do suggest.
Approach 1
type Foo interface {
methodA()
}
type Bar struct {
}
func (b Bar) methodA () {
...
}
func (b Bar) methodB () {
...
}
Approach 2
type Foo interface {
methodA()
}
type Bar struct {
Foo // this can be initialized with any concrete implementation of Foo
}
func (b Bar) methodB () {
...
}
Also, it will be great if it can be pointed out in which scenarios above approaches are better fit for? Thanks!
Technical note: first method assures you (besides mistakes in initializing the struct) you can call methodA on Bar, second one don't because you have to initialize the interface field with something respecting that interface to not have a nil deference error.
Note that using the second method methodA is not called on Bar but on the Foo embedded object!
Second method is useful if you have a common implementation that can be shared by many objects and is self containing, i.e. consider you wanna know if an object implements a Log method to be sure you can log something with that object: in this case you can have a method that returns a Logger and set the interface field with that. Example follows:
package main
import "fmt"
type Logger interface {
Log(string)
}
type ConsoleLogger struct {} // See? No external dependencies
func (Cl ConsoleLogger) Log(msg string) {
fmt.Println(msg)
}
type A1 struct {
Logger
}
type A2 struct {
Logger
}
func main() {
a := A1{ConsoleLogger{}}
b := A2{ConsoleLogger{}}
a.Log("Test")
b.Log("Test")
}
Embedding objects is useful for dispatching method calls, remember it's just sintactic sugar in the end so besides passing the containing object you don't have any way to use its fields.
If Logger interface had to use outer object (A1 and A2) data in some sort of way than this method would be awkward because you would have to initialize the interface object which would then store some reference to the needed data with a waste of memory in some cases.
IMHO method one forces you to write more code but you are more free in the interface implementation and you can mix the two approaches by embedding a Logger and then override the Log method in A1 struct.
Additionally, you can nonetheless pass something to build something implementing an interface:
package main
import "fmt"
type Logger interface {
Log(string)
}
type ConsoleLogger struct {
Prepend string // string to prepend to log message
}
func (Cl ConsoleLogger) Log(msg string) {
fmt.Println(Cl.Prepend + "-" + msg)
}
type A1 struct {
Logger
}
type A2 struct {
Logger
}
func (a A2) Log(msg string) { // Overriding implementation
fmt.Println("In A2")
a.Logger.Log(msg) // Call the original interface value!
}
func main() {
a := A1{ConsoleLogger{"A1"}}
b := A2{ConsoleLogger{"A2"}}
a.Log("Test")
b.Log("Test")
}
This question already has an answer here:
Go embedded struct call child method instead parent method
(1 answer)
Closed 7 years ago.
package main
import "fmt"
type Super struct{}
func (super *Super) name() string {
return "Super"
}
func (super *Super) WhoAmI() {
fmt.Printf("I'm %s.\n", super.name())
}
type Sub struct {
Super
}
func (sub *Sub) name() string {
return "Sub"
}
func main() {
sub := &Sub{Super{}}
sub.WhoAmI()
}
I want to get "I'm Sub", but I get "I'm Super" instead.
I already know sub.WhoAmI will call sub.Super.WhoAmI, but I still want to know if there is a way to get "I'm Sub". In Python when I write following code:
class Super(object):
def name(self):
return "Super"
def WhoAmI(self):
print("I'm {name}".format(name=self.name()))
class Sub(Super):
def name(self):
return "Sub"
if __name__ == "__main__":
sub = Sub()
sub.WhoAmI()
I can get "I'm Sub".
Embedding is not subclassing. There are no superclasses or subclasses in Go. Sub here is not a "child" of Super. It contains a Super. You can't do you're trying to do. You need to organize your code in a different way so that it's not needed.
For example, here (playground) is a more natural way to do this in Go:
package main
import "fmt"
type Namer interface {
Name() string
}
type Super struct{}
func (sub *Super) Name() string {
return "Super"
}
type Sub struct{}
func (sub *Sub) Name() string {
return "Sub"
}
func WhoAmI(namer Namer) {
fmt.Printf("I'm %s.\n", namer.Name())
}
func main() {
sub := &Sub{}
WhoAmI(sub)
}
Rather than focus on classes (which Go doesn't have), this focuses on interfaces. It's not a question of what things are, it's a question of what they can do. This is a very powerful approach to programming, and in practice is often much more flexible and less error-prone than inheritance abstractions.
Think of functions in Go as if they all belong to a single namespace. Go really doesn’t have classes, methods, or inheritance, so what you’re attempting will never work the way you intend.
To put it another way, when you define a function like this:
func (f *Foo) DoStuff()
You can imagine it really being defined as:
func DoStuff(f *Foo)
So you might notice why Go chose to call the name function on your Super struct—it was the only function signature that matched. (Note that in your WhoAmI function super is defined as super *Super so Go matches it up with the corresponding function of the same type.)
As for how you might do this the Go way, try using interfaces:
http://play.golang.org/p/8ELw-9e7Re
package main
import "fmt"
type Indentifier interface {
WhoAmI() string
}
type A struct{}
func (a *A) WhoAmI() string {
return "A"
}
type B struct{}
func (b *B) WhoAmI() string {
return "B"
}
func doSomething(x Indentifier) {
fmt.Println("x is a", x.WhoAmI())
}
func main() {
doSomething(&A{})
doSomething(&B{})
}