Skip to content

Instantly share code, notes, and snippets.

@santosh
Created June 6, 2019 07:51
Show Gist options
  • Save santosh/ddef100bf4dfe397e1d872ef0333b502 to your computer and use it in GitHub Desktop.
Save santosh/ddef100bf4dfe397e1d872ef0333b502 to your computer and use it in GitHub Desktop.
Composition with Go. #golang
package main
import "fmt"
// Board represents a surface we can work on
type Board struct {
NailsNeeded int
NailsDriven int
}
// Mallet is a tool that pounds in nails.
type Mallet struct {
}
type Crowbar struct {
}
type Contractor struct {
}
// Toolbox can contain any number of tools
type Toolbox struct {
NailDriver
NailPuller
nails int
}
// NailDriver represents behavior to drive nails into a board
type NailDriver interface {
DriveNail(nailSupply *int, b *Board)
}
// NailPuller represents behavior to remove nails from the board
type NailPuller interface {
PullNail(nailSupply *int, b *Board)
}
// NailDrivePuller represents behavior to drive/remove nails from a board
type NailDrivePuller interface {
NailDriver
NailPuller
}
func (Mallet) DriveNail(nailSupply *int, b *Board) {
// Take the nail out of the supply
*nailSupply--
// Pound the nail into the board
b.NailsDriven++
fmt.Println("Mallet: pounded nail into the board.")
}
func (Crowbar) PullNail(nailSupply *int, b *Board) {
// Yank a nail out of the board
b.NailsDriven--
// Put that nail back into the supply
*nailSupply++
fmt.Println("Crowbar: yanked nail out of the board.")
}
// Fasten will drive nails into a board
func (Contractor) Fasten(d NailDriver, nailSupply *int, b *Board) {
for b.NailsDriven < b.NailsNeeded {
d.DriveNail(nailSupply, b)
}
}
// Unfasten will remove nails from a board
func (Contractor) Unfasten(p NailPuller, nailSupply *int, b *Board) {
for b.NailsDriven > b.NailsNeeded {
p.PullNail(nailSupply, b)
}
}
// ProcessBoards works against boards.
func (c Contractor) ProcessBoards(dp NailDrivePuller, nailSupply *int, boards []Board) {
for i := range boards {
b := &boards[i]
fmt.Printf("Contractor: examining board #%d: %+v\n", i+1, b)
switch {
case b.NailsDriven < b.NailsNeeded:
c.Fasten(dp, nailSupply, b)
case b.NailsDriven > b.NailsNeeded:
c.Unfasten(dp, nailSupply, b)
}
}
}
// displayState provide information about all the boards
func displayState(tb *Toolbox, boards []Board) {
fmt.Printf("Box: %#v\n", tb)
fmt.Println("Boards:")
for _, b := range boards {
fmt.Printf("\t%+v\n", b)
}
fmt.Println()
}
func main() {
// Inventory of old boards to remove, and the new boards
// that will replace them
boards := []Board{
// Botten boards to be removed
{NailsDriven: 3},
{NailsDriven: 1},
{NailsDriven: 6},
// Fresh boards to be fastened
{NailsNeeded: 6},
{NailsNeeded: 9},
{NailsNeeded: 4},
}
tb := Toolbox{
NailDriver: Mallet{},
NailPuller: Crowbar{},
nails: 10,
}
// Display the current state of our toolbox and boards
displayState(&tb, boards)
var c Contractor
c.ProcessBoards(&tb, &tb.nails, boards)
// Display the current state of our toolbox and boards
displayState(&tb, boards)
}
// Blog post at: https://www.ardanlabs.com/blog/2015/09/composition-with-go.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment