Dependency Inversion Principle in Go
In Go, the Dependency Inversion Principle (DIP) can be enforced using interfaces. You simply define what you need in an interface and accept implementations of it.
But what if the type returned by an interface itself should itself conform to an interface? In this case we can use type aliases and define anonymous interfaces. This approach is not perfect and the reason is stated after the example.
Here is an example. In package main, we want to avoid using a concrete struct from package amazon. We just want to define an interface and use an implementation provided by an otherwise replacable package amazon.
package main
import "amazon"
type Store interface {
Sell(string) Item
}
type Item = interface { // <-- alias
Price() uint
}
func main() {
var store Store = amazon.Store{}
var item Item = store.Sell()
print(item.Price())
}
package amazon
type itemInterface = interface { // <-- alias
Price() uint
}
type Store struct {}
func (Store) Sell(id string) itemInterface {
return bookStruct{}
}
type bookStruct struct {}
func (bookStruct) Price() uint { return 999 }
However, this is not an ideal approach, because now the interface exists in two packages. Ideally, the amazon package should not be aware of the interface, it should only provide the implementation. Just like it does not define any interface for its Store struct.
We can address this issue by moving out our leaking interface (i.e., the item) to its own package.
package main import "amazon" import "item" type Store interface { Sell(string) item.Item } func main() { var st Store = amazon.Store{} var it item.Item = st.Sell() print(it.Price()) }
package amazon import "book" type Store struct {} func (Store) Sell(id string) item.Item { return book.bookStruct{} }
package book type bookStruct struct {} func (bookStruct) Price() uint { return 999 }
package item type Item interface { Price() uint }
With this change, the Store struct provided by the amazon package is freed from repeating the Store interface expected in its user (i.e., the main package) The book package is freed from defining any interface. The main package uses the Item interface to define its dependency interface.