-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstate_machine.go
More file actions
101 lines (89 loc) · 2.78 KB
/
state_machine.go
File metadata and controls
101 lines (89 loc) · 2.78 KB
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
package statemachine
import (
"fmt"
"strings"
)
type stateMachine[S, E ID, C any] struct {
machineId string
stateMap stateMap[S, E, C]
ready bool
failCallback FailCallback[S, E, C]
err error
}
func newStateMachine[S, E ID, C any](stateMap stateMap[S, E, C]) *stateMachine[S, E, C] {
return &stateMachine[S, E, C]{
stateMap: stateMap,
}
}
func (s *stateMachine[S, E, C]) GetMachineId() string {
return s.machineId
}
func (s *stateMachine[S, E, C]) FireEvent(stateId S, event E, ctx C) (r S, err error) {
if !s.ready {
return r, NewError("状态机尚未构建,不能工作")
}
transition := s.routeTransition(stateId, event, ctx)
// 没有找到对应的transition,可能是没定义,也可能是条件满足
if transition == nil {
if s.failCallback != nil {
s.failCallback(stateId, event, ctx)
}
return stateId, nil
}
state, err := transition.transit(ctx, false)
if err != nil {
return r, err
}
return state.id, nil
}
func (s *stateMachine[S, E, C]) Verify(stateId S, event E) bool {
transitions := s.getEventTransitions(stateId, event)
return len(transitions) != 0
}
func (s *stateMachine[S, E, C]) ShowStateMachine() {
builder := strings.Builder{}
builder.WriteString("-----StateMachine:" + s.machineId + "-------")
for stateId, state := range s.stateMap {
builder.WriteString(fmt.Sprintf("State: %v\n", stateId))
for _, transition := range state.getAllEventTransitions() {
builder.WriteString(fmt.Sprintf(" Transition:%s\n", transition))
}
}
builder.WriteString("------------------------")
fmt.Println(builder.String())
}
func (s *stateMachine[S, E, C]) GeneratePlantUML() string {
builder := strings.Builder{}
builder.WriteString("@startuml\n")
for _, state := range s.stateMap {
for _, transition := range state.getAllEventTransitions() {
builder.WriteString(fmt.Sprintf("%v --> %v : %v\n", transition.source.id, transition.target.id, transition.event))
}
}
builder.WriteString("@enduml")
return builder.String()
}
func (s *stateMachine[S, E, C]) routeTransition(stateId S, event E, ctx C) *Transition[S, E, C] {
transitions := s.getEventTransitions(stateId, event)
if len(transitions) == 0 {
return nil
}
var transit *Transition[S, E, C]
for _, transition := range transitions {
if transition.condition == nil {
transit = transition
} else if transition.condition(ctx) {
transit = transition
break
}
}
return transit
}
func (s *stateMachine[S, E, C]) createAndGetState(stateId S) *state[S, E, C] {
return s.stateMap.createAndGet(stateId)
}
func (s *stateMachine[S, E, C]) getEventTransitions(stateId S, event E) []*Transition[S, E, C] {
sourceState := s.stateMap.createAndGet(stateId)
return sourceState.getEventTransitions(event)
}
var _ StateMachine[int, int, int] = (*stateMachine[int, int, int])(nil)