Skip to content

Commit

Permalink
Code for chapter 10.
Browse files Browse the repository at this point in the history
  • Loading branch information
ardan-bkennedy committed May 25, 2016
1 parent d849e6b commit 96200b8
Show file tree
Hide file tree
Showing 7 changed files with 517 additions and 254 deletions.
139 changes: 82 additions & 57 deletions chapter10/listing01/listing01.go
Original file line number Diff line number Diff line change
@@ -1,97 +1,122 @@
// Sample program demonstrating struct composition.
package main

import "fmt"
import (
"errors"
"fmt"
"math/rand"
"time"
)

func init() {
rand.Seed(time.Now().UnixNano())
}

// =============================================================================

// EOD represents the end of the data stream.
var EOD = errors.New("EOD")

// Board represents a surface we can work on.
type Board struct {
NailsNeeded int
NailsDriven int
// Data is the structure of the data we are copying.
type Data struct {
Line string
}

// =============================================================================

// Mallet is a tool that pounds in nails.
type Mallet struct{}
// Xenia is a system we need to pull data from.
type Xenia struct{}

// DriveNail pounds a nail into the specified board.
func (Mallet) DriveNail(nailSupply *int, b *Board) {
*nailSupply--
b.NailsDriven++
fmt.Println("Mallet: pounded nail into the board.")
// Pull knows how to pull data out of Xenia.
func (Xenia) Pull(d *Data) error {
switch rand.Intn(10) {
case 1, 9:
return EOD

case 5:
return errors.New("Error reading data from Xenia")

default:
d.Line = "Data"
fmt.Println("In:", d.Line)
return nil
}
}

// Crowbar is a tool that removes nails.
type Crowbar struct{}
// Pillar is a system we need to store data into.
type Pillar struct{}

// PullNail yanks a nail out of the specified board.
func (Crowbar) PullNail(nailSupply *int, b *Board) {
b.NailsDriven--
*nailSupply++
fmt.Println("Crowbar: yanked nail out of the board.")
// Store knows how to store data into Pillar.
func (Pillar) Store(d Data) error {
fmt.Println("Out:", d.Line)
return nil
}

// =============================================================================

// Toolbox can contains a Mallet and a Crowbar.
type Toolbox struct {
Mallet
Crowbar

nails int
// System wraps Xenia and Pillar together into a single system.
type System struct {
Xenia
Pillar
}

// =============================================================================

// Contractor carries out the task of securing boards.
type Contractor struct{}
// IO provides support to copy bulk data.
type IO struct{}

// Fasten will drive nails into a board.
func (Contractor) Fasten(m Mallet, nailSupply *int, b *Board) {
for b.NailsDriven < b.NailsNeeded {
m.DriveNail(nailSupply, b)
// pull knows how to pull bulks of data from Xenia.
func (IO) pull(x *Xenia, data []Data) (int, error) {
for i := range data {
if err := x.Pull(&data[i]); err != nil {
return i, err
}
}

return len(data), nil
}

// Unfasten will remove nails from a board.
func (Contractor) Unfasten(cb Crowbar, nailSupply *int, b *Board) {
for b.NailsDriven > b.NailsNeeded {
cb.PullNail(nailSupply, b)
// store knows how to store bulks of data from Pillar.
func (IO) store(p *Pillar, data []Data) error {
for _, d := range data {
if err := p.Store(d); err != nil {
return err
}
}
}

// ProcessBoards works against boards.
func (c Contractor) ProcessBoards(tb *Toolbox, nailSupply *int, boards []Board) {
for i := range boards {
b := &boards[i]
return nil
}

fmt.Printf("Contractor: examining board #%d: %+v\n", i+1, b)
// Copy knows how to pull and store data from the System.
func (io IO) Copy(sys *System, batch int) error {
for {
data := make([]Data, batch)

switch {
case b.NailsDriven < b.NailsNeeded:
c.Fasten(tb.Mallet, nailSupply, b)
i, err := io.pull(&sys.Xenia, data)
if i > 0 {
if err := io.store(&sys.Pillar, data[:i]); err != nil {
return err
}
}

case b.NailsDriven > b.NailsNeeded:
c.Unfasten(tb.Crowbar, nailSupply, b)
if err != nil {
return err
}
}
}

// =============================================================================

// main is the entry point for the application.
func main() {
boards := []Board{
{NailsDriven: 3},
{NailsNeeded: 2},
}

tb := Toolbox{
Mallet: Mallet{},
Crowbar: Crowbar{},
nails: 10,
// Initialize the system for use.
sys := System{
Xenia: Xenia{},
Pillar: Pillar{},
}

var c Contractor
c.ProcessBoards(&tb, &tb.nails, boards)
var io IO
if err := io.Copy(&sys, 3); err != EOD {
fmt.Println(err)
}
}
151 changes: 88 additions & 63 deletions chapter10/listing02/listing02.go
Original file line number Diff line number Diff line change
@@ -1,109 +1,134 @@
// Sample program demonstrating decoupling with interfaces.
package main

import "fmt"
import (
"errors"
"fmt"
"math/rand"
"time"
)

func init() {
rand.Seed(time.Now().UnixNano())
}

// =============================================================================

// EOD represents the end of the data stream.
var EOD = errors.New("EOD")

// Board represents a surface we can work on.
type Board struct {
NailsNeeded int
NailsDriven int
// Data is the structure of the data we are copying.
type Data struct {
Line string
}

// =============================================================================

// NailDriver represents behavior to drive nails into a board.
type NailDriver interface {
DriveNail(nailSupply *int, b *Board)
// Puller declares behavior for pulling data.
type Puller interface {
Pull(d *Data) error
}

// NailPuller represents behavior to remove nails into a board.
type NailPuller interface {
PullNail(nailSupply *int, b *Board)
// Storer declares behavior for storing data.
type Storer interface {
Store(d Data) error
}

// =============================================================================

// Mallet is a tool that pounds in nails.
type Mallet struct{}
// Xenia is a system we need to pull data from.
type Xenia struct{}

// DriveNail pounds a nail into the specified board.
func (Mallet) DriveNail(nailSupply *int, b *Board) {
*nailSupply--
b.NailsDriven++
fmt.Println("Mallet: pounded nail into the board.")
// Pull knows how to pull data out of Xenia.
func (Xenia) Pull(d *Data) error {
switch rand.Intn(10) {
case 1, 9:
return EOD

case 5:
return errors.New("Error reading data from Xenia")

default:
d.Line = "Data"
fmt.Println("In:", d.Line)
return nil
}
}

// Crowbar is a tool that removes nails.
type Crowbar struct{}
// Pillar is a system we need to store data into.
type Pillar struct{}

// PullNail yanks a nail out of the specified board.
func (Crowbar) PullNail(nailSupply *int, b *Board) {
b.NailsDriven--
*nailSupply++
fmt.Println("Crowbar: yanked nail out of the board.")
// Store knows how to store data into Pillar.
func (Pillar) Store(d Data) error {
fmt.Println("Out:", d.Line)
return nil
}

// =============================================================================

// Toolbox can contains a Mallet and a Crowbar.
type Toolbox struct {
Mallet
Crowbar

nails int
// System wraps Xenia and Pillar together into a single system.
type System struct {
Xenia
Pillar
}

// =============================================================================

// Contractor carries out the task of securing boards.
type Contractor struct{}
// IO provides support to copy bulk data.
type IO struct{}

// 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)
// pull knows how to pull bulks of data from any Puller.
func (IO) pull(p Puller, data []Data) (int, error) {
for i := range data {
if err := p.Pull(&data[i]); err != nil {
return i, err
}
}

return len(data), nil
}

// 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)
// store knows how to store bulks of data from any Storer.
func (IO) store(s Storer, data []Data) error {
for _, d := range data {
if err := s.Store(d); err != nil {
return err
}
}
}

// ProcessBoards works against boards.
func (c Contractor) ProcessBoards(tb *Toolbox, nailSupply *int, boards []Board) {
for i := range boards {
b := &boards[i]
return nil
}

fmt.Printf("Contractor: examining board #%d: %+v\n", i+1, b)
// Copy knows how to pull and store data from the System.
func (io IO) Copy(sys *System, batch int) error {
for {
data := make([]Data, batch)

switch {
case b.NailsDriven < b.NailsNeeded:
c.Fasten(tb.Mallet, nailSupply, b)
i, err := io.pull(&sys.Xenia, data)
if i > 0 {
if err := io.store(&sys.Pillar, data[:i]); err != nil {
return err
}
}

case b.NailsDriven > b.NailsNeeded:
c.Unfasten(tb.Crowbar, nailSupply, b)
if err != nil {
return err
}
}
}

// =============================================================================

// main is the entry point for the application.
func main() {
boards := []Board{
{NailsDriven: 3},
{NailsNeeded: 2},
}

tb := Toolbox{
Mallet: Mallet{},
Crowbar: Crowbar{},
nails: 10,
// Initialize the system for use.
sys := System{
Xenia: Xenia{},
Pillar: Pillar{},
}

var c Contractor
c.ProcessBoards(&tb, &tb.nails, boards)
var io IO
if err := io.Copy(&sys, 3); err != EOD {
fmt.Println(err)
}
}
Loading

0 comments on commit 96200b8

Please sign in to comment.