Dependency Inversion
An example of Dependency Inversion with Go. The program looks a little long and drawn out. But, it’s really simple. The button is separated from the Lamp/Fan by an abstraction. That abstraction is from the interface.
Dependency Inversion utilizes Dependency Injection. What that means
is the button connects to anything with a “device interface.” Anything
that has status() bool
, button(bool)
and name() string
.
As you can see at the bottom of the code, the butto can connect to a Lamp or a Fan.
package main
import (
"fmt"
)
type device interface {
status() bool
button(bool)
name() string
}
type Lamp struct {
light bool
}
func (l *Lamp) button(s bool) {
fmt.Printf("turning on lamp: %v\n", s)
l.light = s
}
func (l *Lamp) status() bool {
return l.light
}
func (l *Lamp) name() string {
return "lamp"
}
type Fan struct {
on bool
}
func (f *Fan) button(s bool) {
fmt.Printf("turning on fan: %v\n", s)
f.on = s
}
func (f *Fan) status() bool {
return f.on
}
func (f *Fan) name() string {
return "Fan"
}
type Button struct {
d device
}
func (b *Button) connect(d device) {
b.d = d
}
func (b *Button) button(state bool) {
b.d.button(state)
}
func (b *Button) status() (bool, string) {
return b.d.status(), b.d.name()
}
func main() {
lamp := Lamp{}
button := Button{}
button.connect(&lamp)
button.button(true)
state, name := button.status()
fmt.Printf("Status: %v,%v\n", state, name)
fan := Fan{}
button.connect(&fan)
button.button(true)
fmt.Printf("Status: %v,%v\n", state, name)
button.button(false)
fmt.Printf("Status: %v,%v\n", state, name)
}
3 Goals
There are 3 goals.
-
Avoid Rigidity: The software should be easy change. If the software is built with independent components, that change should work by only affecting the intended parts.
-
Avoid Fragility: The change shouldn’t break unexpected parts.
-
Avoid Immobility: Reuse. Parts can be disentangled from the current application.
Protocol/Interface
Protocol in Swift and Interface in Go provide a way to separate the button from the device.
protocol Device {
func state() -> Bool
func changeState(setting: Bool)
var type:String {get set}
}
class Lamp: Device {
var type = "Lamp"
var light:Bool = false
func state() -> Bool {
return light
}
func changeState(setting: Bool) {
light = setting
}
}
class Button {
var device:Device
init(device: Device) {
self.device = device
}
func setState(setState: Bool) {
device.changeState(setting: setState)
}
func getState() -> Bool {
return device.state()
}
}