-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathStateMachineBug.cs
131 lines (108 loc) · 3.99 KB
/
StateMachineBug.cs
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
using System;
using Stateless;
using Stateless.Graph;
namespace BulkOperations
{
public class StateMachineBug
{
public static void Run()
{
var bug = new StateMachineBug("Incorrect stock count");
bug.Assign("Joe");
bug.Defer();
bug.Assign("Harry");
bug.Assign("Fred");
bug.Close();
Console.WriteLine();
Console.WriteLine("State machine:");
Console.WriteLine(bug.ToDotGraph());
}
private enum State
{
Open,
Assigned,
Deferred,
Closed
}
private enum Trigger
{
Assign,
Defer,
Close
}
private readonly StateMachine<State, Trigger> _machine;
// The TriggerWithParameters object is used when a trigger requires a payload.
private readonly StateMachine<State, Trigger>.TriggerWithParameters<string> _assignTrigger;
private readonly string _title;
private string _assignee;
/// <summary>
/// Constructor for the Bug class
/// </summary>
/// <param name="title">The title of the bug report</param>
public StateMachineBug(string title)
{
_title = title;
// Instantiate a new state machine in the Open state
_machine = new StateMachine<State, Trigger>(State.Open);
// Instantiate a new trigger with a parameter.
_assignTrigger = _machine
.SetTriggerParameters<string>(Trigger.Assign);
// Configure the Open state
_machine.Configure(State.Open)
.Permit(Trigger.Assign, State.Assigned);
// Configure the Assigned state
_machine.Configure(State.Assigned)
.SubstateOf(State.Open)
.OnEntryFrom(_assignTrigger, OnAssigned) // This is where the TriggerWithParameters is used. Note that the TriggerWithParameters object is used, not something from the enum
.PermitReentry(Trigger.Assign)
.Permit(Trigger.Close, State.Closed)
.Permit(Trigger.Defer, State.Deferred)
.OnExit(OnDeassigned);
// Configure the Deferred state
_machine.Configure(State.Deferred)
.OnEntry(() => _assignee = null)
.Permit(Trigger.Assign, State.Assigned);
}
public void Close()
{
_machine.Fire(Trigger.Close);
}
public void Assign(string assignee)
{
// This is how a trigger with parameter is used, the parameter is supplied to the state machine as a parameter to the Fire method.
_machine.Fire(_assignTrigger, assignee);
}
public bool CanAssign => _machine.CanFire(Trigger.Assign);
public void Defer()
{
_machine.Fire(Trigger.Defer);
}
/// <summary>
/// This method is called automatically when the Assigned state is entered, but only when the trigger is _assignTrigger.
/// </summary>
/// <param name="assignee"></param>
private void OnAssigned(string assignee)
{
if (_assignee != null && assignee != _assignee)
SendEmailToAssignee("Don't forget to help the new employee!");
_assignee = assignee;
SendEmailToAssignee("You own it.");
}
/// <summary>
/// This method is called when the state machinie exits the Assigned state
/// </summary>
private void OnDeassigned()
{
SendEmailToAssignee("You're off the hook.");
}
private void SendEmailToAssignee(string message)
{
// ReSharper disable once LocalizableElement
Console.WriteLine("{0}, RE {1}: {2}", _assignee, _title, message);
}
public string ToDotGraph()
{
return UmlDotGraph.Format(_machine.GetInfo());
}
}
}