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.

Playground

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()

  }

}