问题的描述
最近在改仿真软件的状态切换 ,什么意思呢,这东西有点像个播放器,但是不仅仅是播放暂停那么简单。首先我们画一个图 ,以一个图说明:
通过以前的面向对象设计经验我们知道有一种叫状态机的东西, 简而言之就是把每个状态 通过节点对象包装 ,节点是什么类型就是当前处于什么状态,看到箭头的方向没 代表到另一个状态去 ,到的这个过程 我们 把抽象成状态对象的方法。基本思路是把节点抽象成泛化对象,能不能到哪个 到的过程中出现了异常又怎么办 ,分而治之的思想充分的体现了面向对象的威力。 原项目根本没有考虑到任何类似状态机这种的东西 ,全是用的判断,与业务嵌入太重。实际的比理想化的难得的多,但是我们不怕 不管怎样我们先开个头。
实现
首先不管如何所有的指令我们要罗列出来(启动,运行,暂停也叫冻结,停止,快照):
1 public enum Command
2 {
3 Start,
4 ToRun,
5 ToPause,
6 ToStop,
7 Snap
8 }
然后是对节点状态进行泛化,说白了就是抽象出几个状态了类,然后他们有一个共同基类,按钮是否变灰就是根据状态,来的。某个指令能不能执行显然这个是所有泛化对象都要有的,所以我们作为基类方法。
1 public class BaseState
2 {
3 public string StateInfo { get; set; } = "未知状态";
4 public string ErrorInfo { get; set; }
5 public void Error()
6 {
7
8 }
9
10 public virtual void Execute(Command cmd)
11 {
12
13 }
14 public virtual bool CanExecute(Command cmd)
15 {
16 return true;
17 }
18
19 }
然后是各个具体节点的状态类,别看代码这么长,都是些冗长重复的东西。
1 public class Run : BaseState
2 {
3 public Run()
4 {
5 StateInfo = "运行";
6 Console.WriteLine("状态变为运行");
7 }
8 public void ToStop()
9 {
10 Console.WriteLine("转到停止中...");
11 Envierment.st = new Stop();
12 }
13
14 public void ToPause()
15 {
16
17 Console.WriteLine("转到暂停中...");
18 Envierment.st = new Pause();
19 }
20
21 public void Snap()
22 {
23 Console.WriteLine("快照中...");
24 Console.WriteLine("快照完成...");
25 }
26
27 public override void Execute(Command cmd)
28 {
29 //base.Execute(cmd);
30 if (cmd == Command.ToStop)
31 ToStop();
32 else if (cmd == Command.ToPause)
33 ToPause();
34 else if (cmd == Command.Snap)
35 Snap();
36 else
37 {
38
39 }
40 }
41 public override bool CanExecute(Command cmd)
42 {
43 //return base.CanExecute(cmd);
44 if (cmd == Command.ToStop || cmd == Command.ToPause || cmd == Command.Snap)
45 return true;
46 else
47 return false;
48 }
49
50 }
51
52 public class Pause : BaseState
53 {
54 public Pause()
55 {
56 StateInfo = "暂停";
57 Console.WriteLine("状态变为暂停");
58 }
59 public void ToRun()
60 {
61 Console.WriteLine("转到运行中...");
62
63 Envierment.st = new Run();
64 }
65 public void ToStop()
66 {
67 Console.WriteLine("转到停止中...");
68
69 Envierment.st = new Stop();
70 }
71
72 public void Snap()
73 {
74 Console.WriteLine("快照中...");
75 Console.WriteLine("快照完成...");
76 }
77 public override void Execute(Command cmd)
78 {
79 //base.Execute(cmd);
80 if (cmd == Command.ToStop)
81 ToStop();
82 else if (cmd == Command.ToRun)
83 ToRun();
84 else if (cmd == Command.Snap)
85 Snap();
86 else
87 {
88
89 }
90 }
91 public override bool CanExecute(Command cmd)
92 {
93 //return base.CanExecute(cmd);
94 if (cmd == Command.ToStop || cmd == Command.ToRun || cmd == Command.Snap)
95 return true;
96 else
97 return false;
98 }
99 }
100
101 public class Stop : BaseState
102 {
103 public Stop()
104 {
105 StateInfo = "停止";
106
107 Console.WriteLine("状态变为停止");
108 }
109 public void Start()
110 {
111 Console.WriteLine("转到暂停中...");
112 Envierment.st = new Pause();
113 }
114
115 public override void Execute(Command cmd)
116 {
117 //base.Execute(cmd);
118 if (cmd == Command.Start)
119 Start();
120 else
121 {
122
123 }
124 }
125 public override bool CanExecute(Command cmd)
126 {
127 //return base.CanExecute(cmd);
128 if (cmd == Command.Start)
129 return true;
130 else
131 return false;
132 }
133 }
整体使用
如何用?我们的思想是new一个对象出来放那,然后这个实例他就代表了一个全局的状态,状态切换走的时候 我们new新的对象代替,他们都是基于同一个父类,不同子类是否能执行某些状态切换方法在其内部进行,一个类就代表了一个特定类型的节点,如此实现分而治之的效果。初始是stop状态
1 public class Envierment
2 {
3 public static BaseState st;
4 public static void Initial()
5 {
6 st = new Stop();
7 }
8 }
1 <WrapPanel>
2 <Button Name="btn_start" Height="25" Width="50" Click="btncmd_Click">启动</Button>
3 <Button Name="btn_torun" Height="25" Width="50" Click="btncmd_Click">运行</Button>
4 <Button Name="btn_topause" Height="25" Width="50" Click="btncmd_Click">暂停</Button>
5 <Button Name="btn_snap" Height="25" Width="50" Click="btncmd_Click">快照</Button>
6 <Button Name="btn_tostop" Height="25" Width="50" Click="btncmd_Click">停止</Button>
7 </WrapPanel>
8 <WrapPanel>
9 <Label Height="25">当前状态:</Label>
10 <Label Height="25" Name="lab_state">停止</Label>
11 </WrapPanel>
1 public Window1()
2 {
3 InitializeComponent();
4 Envierment.Initial();
5 lab_state.Content = Envierment.st.StateInfo;
6 }
7 private void btncmd_Click(object sender, RoutedEventArgs e)
8 {
9 Button btn = sender as Button;
10 Command cmd = Command.ToStop;
11
12 if (btn.Name == "btn_start")
13 cmd = Command.Start;
14 if (btn.Name == "btn_torun")
15 cmd = Command.ToRun;
16 if (btn.Name == "btn_topause")
17 cmd = Command.ToPause;
18 if (btn.Name == "btn_snap")
19 cmd = Command.Snap;
20 if (btn.Name == "btn_tostop")
21 cmd = Command.ToStop;
22
23 Envierment.st.Execute(cmd);
24
25 if (Envierment.st.CanExecute(Command.Start))
26 btn_start.IsEnabled = true;
27 else
28 btn_start.IsEnabled = false;
29
30 if (Envierment.st.CanExecute(Command.ToRun))
31 btn_torun.IsEnabled = true;
32 else
33 btn_torun.IsEnabled = false;
34
35 if (Envierment.st.CanExecute(Command.ToPause))
36 btn_topause.IsEnabled = true;
37 else
38 btn_topause.IsEnabled = false;
39
40 if (Envierment.st.CanExecute(Command.Snap))
41 btn_snap.IsEnabled = true;
42 else
43 btn_snap.IsEnabled = false;
44
45 if (Envierment.st.CanExecute(Command.ToStop))
46 btn_tostop.IsEnabled = true;
47 else
48 btn_tostop.IsEnabled = false;
49
50 lab_state.Content = Envierment.st.StateInfo;
51 }
最终的效果