-
Notifications
You must be signed in to change notification settings - Fork 0
/
door.go
199 lines (164 loc) · 4.48 KB
/
door.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package main
//go:generate dot -Tpng -oDoorStateDiagram.png door.dot
//go:generate dot -Tpng -oDoorObjectHeirarchy.png object_heirarchy.dot
import "errors"
// Door is our model. It has state.
type Door struct {
DoorState
VisitorCount int
LockCount int
}
// DoorState is the state and possible transitions
type DoorState interface {
Can(DoorState) bool
Open(*Door) (DoorState, error)
Close(*Door) (DoorState, error)
Lock(*Door) (DoorState, error)
Unlock(*Door) (DoorState, error)
}
// New creates a new instance of Door initialised with a state
func New(s DoorState) *Door {
return &Door{DoorState: s}
}
// Can is a helper function which returns true if we can transition
// from the current state to the desired state
func (d *Door) Can(n DoorState) bool {
return d.DoorState.Can(n)
}
// Open is a helper function to call the Open transition
// on the current state
func (d *Door) Open() error {
s, err := d.DoorState.Open(d)
if err != nil {
return err
}
d.DoorState = s
return nil
}
// Close is a helper function to call the Close transition
// on the current state
func (d *Door) Close() error {
s, err := d.DoorState.Close(d)
if err != nil {
return err
}
d.DoorState = s
return nil
}
// Lock is a helper function to call the Lock transition
// on the current state
func (d *Door) Lock() error {
s, err := d.DoorState.Lock(d)
if err != nil {
return err
}
d.DoorState = s
return nil
}
// Unlock is a helper function to call the Unlock transition
// on the current state
func (d *Door) Unlock() error {
s, err := d.DoorState.Unlock(d)
if err != nil {
return err
}
d.DoorState = s
return nil
}
// IsOpen returns true if we are in the OpenDoorState
func (d *Door) IsOpen() bool {
_, ok := d.DoorState.(OpenDoorState)
return ok
}
// IsClosed returns true if we are in the ClosedDoorState
func (d *Door) IsClosed() bool {
_, ok := d.DoorState.(ClosedDoorState)
return ok
}
// IsLocked returns true if we are in the LockedDoorState
func (d *Door) IsLocked() bool {
_, ok := d.DoorState.(LockedDoorState)
return ok
}
// ErrIllegalStateTransition is raised if we cannot transiton
var ErrIllegalStateTransition = errors.New("Illegal state transition")
// abstractDoorState is an embedable type that provides default
// implementations for transitions
type abstractDoorState struct{}
func (d abstractDoorState) Can(DoorState) bool {
return false
}
func (d abstractDoorState) Open(ctx *Door) (DoorState, error) {
return &abstractDoorState{}, ErrIllegalStateTransition
}
func (d abstractDoorState) Close(ctx *Door) (DoorState, error) {
return &abstractDoorState{}, ErrIllegalStateTransition
}
func (d abstractDoorState) Lock(ctx *Door) (DoorState, error) {
return &abstractDoorState{}, ErrIllegalStateTransition
}
func (d abstractDoorState) Unlock(ctx *Door) (DoorState, error) {
return &abstractDoorState{}, ErrIllegalStateTransition
}
// OpenDoorState is the open door state
type OpenDoorState struct {
abstractDoorState
}
// Can returns true if we can transition to the desired
// state from the current OpenDoorState
func (s OpenDoorState) Can(n DoorState) bool {
switch n.(type) {
case ClosedDoorState:
return true
default:
return false
}
}
// Close transitions from OpenDoorState to ClosedDoorState
func (s OpenDoorState) Close(door *Door) (DoorState, error) {
return ClosedDoorState{}, nil
}
// ClosedDoorState is the closed door state
type ClosedDoorState struct {
abstractDoorState
}
// Can returns true if we can transition to the desired
// state from the current ClosedDoorState
func (s ClosedDoorState) Can(n DoorState) bool {
switch n.(type) {
case OpenDoorState:
return true
case LockedDoorState:
return true
default:
return false
}
}
// Open transitions from ClosedDoorState to OpenDoorState
func (s ClosedDoorState) Open(door *Door) (DoorState, error) {
door.VisitorCount++
return OpenDoorState{}, nil
}
// Lock transitions from ClosedDoorState to LockedDoorState
func (s ClosedDoorState) Lock(door *Door) (DoorState, error) {
door.LockCount++
return LockedDoorState{}, nil
}
// LockedDoorState is the locked door state
type LockedDoorState struct {
abstractDoorState
}
// Can returns true if we can transition to the desired
// state from the current LockedDoorState
func (s LockedDoorState) Can(n DoorState) bool {
switch n.(type) {
case ClosedDoorState:
return true
default:
return false
}
}
// Unlock transitions from LockedDoorState to ClosedDoorState
func (s LockedDoorState) Unlock(door *Door) (DoorState, error) {
return ClosedDoorState{}, nil
}