Last active
November 19, 2015 03:49
-
-
Save caelifer/826948cb8ee995633547 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "fmt" | |
// board | |
type Board struct { | |
NailsIn, NailsNeeded int | |
} | |
// fasets | |
type Nail struct{} | |
// faset tool interface | |
type NailPuller interface { | |
PullNail(b *Board) | |
} | |
type NailDriver interface { | |
DriveNail(b *Board) | |
} | |
// tools | |
type Mallet struct{} | |
func (Mallet) String() string { | |
return "Mallet" | |
} | |
// Implement NailDriver interface | |
func (Mallet) DriveNail(b *Board) { | |
b.NailsIn++ | |
} | |
type Crowbar struct{} | |
func (Crowbar) String() string { | |
return "Crowbar" | |
} | |
func (c Crowbar) PullNail(b *Board) { | |
if b.NailsIn > 0 { | |
b.NailsIn-- | |
} else { | |
fmt.Printf("%s: no nails in this board; what gives!?\n", c) | |
} | |
} | |
// Contractor carries out the task of securing boards. | |
type Contractor struct{} | |
func (Contractor) resupplyNails(nailSupply chan<- Nail) { | |
// fill nail supply with nails | |
for { | |
select { | |
case nailSupply <- Nail{}: | |
fmt.Println("Contractor: added one nail to my nail supply.") | |
default: | |
fmt.Println("Contractor: nail supply is full") | |
return | |
} | |
} | |
} | |
// fasten will drive nails into a board. | |
func (c Contractor) fasten(d NailDriver, nailSupply chan Nail, b *Board) { | |
for b.NailsIn < b.NailsNeeded { | |
GET_NAIL: | |
for { | |
select { | |
case <-nailSupply: | |
break GET_NAIL | |
default: | |
fmt.Println("Contractor: need more nails!") | |
c.resupplyNails(nailSupply) | |
} | |
} | |
d.DriveNail(b) | |
fmt.Printf("Contractor: pounded a nail into the board using %s.\n", d) | |
} | |
} | |
// unfasten will remove nails from a board. | |
func (Contractor) unfasten(p NailPuller, nailSupply chan<- Nail, b *Board) { | |
for b.NailsIn > b.NailsNeeded { | |
p.PullNail(b) | |
fmt.Printf("Contractor: pulled a used nail from the board using %s.\n", p) | |
// return the used nail into our nail supply | |
select { | |
case nailSupply <- Nail{}: | |
fmt.Println("Contractor: put a used nail back into my nail supply.") | |
default: | |
fmt.Println("Contractor: too many nails (nail supply is full), throw this one away.") | |
} | |
} | |
} | |
// processBoards works against boards. | |
func (c Contractor) processBoards(dp Toolbox, nailSupply chan Nail, boards []Board) { | |
for i := range boards { | |
b := &boards[i] | |
fmt.Printf("Contractor: examining board #%d: %+v\n", i+1, b) | |
switch { | |
case b.NailsIn < b.NailsNeeded: | |
c.fasten(dp.NailDriver, nailSupply, b) | |
case b.NailsIn > b.NailsNeeded: | |
c.unfasten(dp.NailPuller, nailSupply, b) | |
} | |
} | |
} | |
// ============================================================================= | |
// Toolbox can contains any number of tools. | |
type Toolbox struct { | |
NailDriver NailDriver | |
NailPuller NailPuller | |
NailSupply chan Nail | |
} | |
// ============================================================================= | |
func main() { | |
// Inventory of old boards to remove, and the new boards | |
// that will replace them. | |
boards := []Board{ | |
// Rotted boards to be removed. | |
{NailsIn: 3}, | |
{NailsIn: 1}, | |
{NailsIn: 6}, | |
// Fresh boards to be fastened. | |
{NailsNeeded: 6}, | |
{NailsNeeded: 9}, | |
{NailsNeeded: 4}, | |
} | |
// Fill a toolbox. | |
tb := Toolbox{ | |
NailDriver: Mallet{}, | |
NailPuller: Crowbar{}, | |
NailSupply: make(chan Nail, 5), | |
} | |
// Display the current state of our toolbox and boards. | |
displayState(tb, boards) | |
// Hire a Contractor and put our Contractor to work. | |
var c Contractor | |
c.processBoards(tb, tb.NailSupply, boards) | |
// Display the new state of our toolbox and boards. | |
displayState(tb, boards) | |
} | |
// displayState provide information about all the boards. | |
func displayState(tb Toolbox, boards []Board) { | |
fmt.Printf("Box: %#v with %d nail(s)\n", tb, len(tb.NailSupply)) | |
fmt.Println("Boards:") | |
for _, b := range boards { | |
fmt.Printf("\t%+v\n", b) | |
} | |
fmt.Println() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Live code - http://play.golang.org/p/EUF7TvMlXk