实现一个状态机

问题的描述

最近在改仿真软件的状态切换 ,什么意思呢,这东西有点像个播放器,但是不仅仅是播放暂停那么简单。首先我们画一个图 ,以一个图说明:

 

 

通过以前的面向对象设计经验我们知道有一种叫状态机的东西, 简而言之就是把每个状态 通过节点对象包装 ,节点是什么类型就是当前处于什么状态,看到箭头的方向没 代表到另一个状态去 ,到的这个过程 我们 把抽象成状态对象的方法。基本思路是把节点抽象成泛化对象,能不能到哪个 到的过程中出现了异常又怎么办 ,分而治之的思想充分的体现了面向对象的威力。 原项目根本没有考虑到任何类似状态机这种的东西 ,全是用的判断,与业务嵌入太重。实际的比理想化的难得的多,但是我们不怕 不管怎样我们先开个头。

实现

首先不管如何所有的指令我们要罗列出来(启动,运行,暂停也叫冻结,停止,快照):

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 }

 

最终的效果

 

posted @ 2024-01-21 22:28  assassinx  阅读(26)  评论(0编辑  收藏  举报