forked from ardanlabs/gotraining
-
Notifications
You must be signed in to change notification settings - Fork 0
/
example2.go
159 lines (120 loc) · 3.77 KB
/
example2.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// All material is licensed under the Apache License Version 2.0, January 2004
// http://www.apache.org/licenses/LICENSE-2.0
// http://play.golang.org/p/QnkL-UIVJN
// Sample program demonstrating composition through embedding.
package main
import "fmt"
// =============================================================================
// Board represents a surface we can work on.
type Board struct {
NailsNeeded int
NailsDriven int
}
// =============================================================================
// NailDriver represents behavior to drive nails into a board.
type NailDriver interface {
DriveNail(nailSupply *int, b *Board)
}
// NailPuller represents behavior to remove nails into a board.
type NailPuller interface {
PullNail(nailSupply *int, b *Board)
}
// NailDrivePuller represents behavior to drive and remove nails into a board.
type NailDrivePuller interface {
NailDriver
NailPuller
}
// =============================================================================
// Mallet is a tool that pounds in nails.
type Mallet struct{}
// DriveNail pounds a nail into the specified board.
func (Mallet) DriveNail(nailSupply *int, b *Board) {
// Take a nail out of the supply.
*nailSupply--
// Pound a nail into the board.
b.NailsDriven++
fmt.Println("Mallet: pounded nail into the board.")
}
// Crowbar is a tool that removes nails.
type Crowbar struct{}
// PullNail yanks a nail out of the specified 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.")
}
// =============================================================================
// Contractor carries out the task of securing boards.
type Contractor 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)
}
}
// 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)
}
}
}
// =============================================================================
// Toolbox can contains any number of tools.
type Toolbox struct {
NailDriver
NailPuller
nails int
}
// =============================================================================
// main is the entry point for the application.
func main() {
// Inventory of old boards to remove, and the new boards
// that will replace them.
boards := []Board{
// Rotted boards to be removed.
{NailsDriven: 3},
{NailsDriven: 1},
{NailsDriven: 6},
// Fresh boards to be fastened.
{NailsNeeded: 6},
{NailsNeeded: 9},
{NailsNeeded: 4},
}
// Fill a toolbox.
tb := Toolbox{
NailDriver: Mallet{},
NailPuller: Crowbar{},
nails: 10,
}
// 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.nails, 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\n", tb)
fmt.Println("Boards:")
for _, b := range boards {
fmt.Printf("\t%+v\n", b)
}
fmt.Println()
}