其他分享
首页 > 其他分享> > 状态模式(一)

状态模式(一)

作者:互联网

本人从事仪器仪表行的软件开发工作,在软件的业务逻辑中,经常需要去对仪器的运行流程进行控制,一种方法就是开启一个while循环,通过循环不断地去查询状态的值,然后在循环内部根据状态值去执行特定的操作。示例代码如下:

 static  void Main(string[] args)
        {
           CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
           Run(StateType.A, cancellationTokenSource.Token);//阻塞了主线程,实际可能会开启线程或者异步去执行
        }

       

       private static void Run(StateType state, CancellationToken token)
        {
            while (token != null && !token.IsCancellationRequested)
            {
                switch (state)
                {
                    case StateType.A:
                        HandleWorkA();
                        state = StateType.B;
                        break;
                    case StateType.B:
                        HandleWorkB();
                        state = StateType.C;
                        break;
                    case StateType.C:
                        HandleWorkC();
                        state = StateType.D;
                        break;
                    case StateType.D:
                        HandleWorkD();
                        state = StateType.E;
                        break;
                    case StateType.E:
                        HandleWorkE();
                        state = StateType.A;
                        break;
                }
                Thread.Sleep(1000);
            }
        }

        private static void HandleWorkE()
        {
            Console.WriteLine("运行业务逻辑E");
        }

        private static void HandleWorkD()
        {
            Console.WriteLine("运行业务逻辑D");
        }

        private static void HandleWorkC()
        {
            Console.WriteLine("运行业务逻辑C");
        }

        private static void HandleWorkB()
        {
            Console.WriteLine("运行业务逻辑B");
        }

        private static void HandleWorkA()
        {
            Console.WriteLine("运行业务逻辑A");
        }
    }
    enum StateType
    {
        A,
        B,
        C,
        D,
        E
    }

以上代码开启了一个循环,在循环中,我们通过switch case 不断地去判断state的值,然后处理相应的业务,在业务处理结束时,我们会更新state的值,从而实现流程的跳转。

观察上面的代码我们可以发现几个特点:

1、状态切换的”动力源“是while循环。在上述代码中,HandleWorkA()、HandleWorkB()等等业务逻辑之所以能够被执行,状态之所以能够切换,其”动力“正是来自于while循环。

2、各个case下执行的代码逻辑是基本相似的。在每个case下,都会执行各自的业务逻辑,并且会决定下一个循环中switch的state值,在本例中就是去执行HandleWorkA()、HandleWorkB()等方法,在执行完这些方法后,状态state进行了更新。

3、新的状态,是由老的状态决定的。在每个case的break之前,其实已经知道下一次循环的状态了。比如在执行case A的业务后,我们就知道,下一个执行的必定是case B的业务。

由此我们想到,如果我们在执行case A的业务之后,直接调用执行case B的业务,那不就不需要while循环来给状态之间的跳转提供”动力“了吗?那是否在caseA 的HandleWorkA()之后调用HandleWorkB()就可以了呢?显然是不行的,因为如果这样做,在调用完HandleWorkB()我们同样还需要考虑运行HandleWorkC()的问题,最后代码就成了以下这样:

  private static void Run(StateType state, CancellationToken token)
        {
            while (token != null && !token.IsCancellationRequested)
            {
                switch (state)
                {
                    case StateType.A:
                        HandleWorkA();
                        HandleWorkB();
                        HandleWorkC();
                        HandleWorkD();
                        HandleWorkE();
                        break;
                }
            }
        }                

究其原因,是因为我们在执行完当前case的业务之后调用新的case的业务时,调用的是具体的方法,因此,我们在代码中必须调用不同的方法。

而上面我们提到”各个case下执行的代码逻辑是基本相似的“,因此我们考虑将每个case下的代码逻辑进行抽象,从而实现统一的调用。由此引出了本文的主题,状态模式,以上代码,使用状态模式的实现如下:

 static  void Main(string[] args)
        {
            StateMachine stateMachine   = new StateMachine(new StateA());
            stateMachine.UpdateState();
        }

 interface IState
    {
        void Handle(StateMachine stateMachine);//把stateMachine传到Handle方法里,因为State业务逻辑可能需要用到stateMachine
    }

    class StateMachine
    {
        IState state;
        public StateMachine(IState initState)
        {
            this.state = initState;
        }
        public void UpdateState()
        {
            state.Handle(this);
        }
    }

   class StateA : IState
    {
        public void Handle(StateMachine stateMachine)
        {

            Console.WriteLine("运行业务逻辑A");
            Thread.Sleep(1000);
            new StateB().Handle(stateMachine);
        }
    }
    class StateB : IState
    {
        public void Handle(StateMachine stateMachine)
        {

            Console.WriteLine("运行业务逻辑B");
            Thread.Sleep(1000);
            new StateC().Handle(stateMachine);
        }
    }
    class StateC : IState
    {
        public void Handle(StateMachine stateMachine)
        {
            Console.WriteLine("运行业务逻辑C");
            Thread.Sleep(1000);
            new StateD().Handle(stateMachine);
        }
    }

    class StateD : IState
    {
        public void Handle(StateMachine stateMachine)
        {
            Console.WriteLine("运行业务逻辑D");
            Thread.Sleep(1000);
            new StateE().Handle(stateMachine);
        }
    }
    class StateE : IState
    {
        public void Handle(StateMachine stateMachine)
        {
            Console.WriteLine("运行业务逻辑E");
            Thread.Sleep(1000);
            new StateA().Handle(stateMachine);
        }
    }

对比两种方式我们写的代码,我们发现了一些改变:

1、switch case没有了,取而代之的是多个State,我们将不同状态要执行的业务逻辑封装到了StateA-StateE中;

2、while循环没有了,状态跳转的实现,是通过在每个状态的Handle方法结束前执行新状态的Handle方法实现的,如在StateA的Handle方法末尾,我们执行了new StateB().Handle(stateMachine);

 

那么在本例中使用状态模式的好处是什么呢?我概括为以下几个方面:

1、对不同状态的业务逻辑进行了封装,代码逻辑的封装性更好

2、去掉了while 和switch case,在新增状态时,只需要定义新的状态类就可以,代码的主调用过程( StateMachine stateMachine = new StateMachine(new StateA()); stateMachine.UpdateState();)不变,因而拓展性更好

3、swit case需要判断所有可能的状态,而在State类中,我们只会关注和State相关的状态,如在StateA中我们只关注StateA执行的业务逻辑DoWorkA,以及它的后续状态StateB。

 

本文中stateMachine.UpdateState();在运行了之后,再没有接受外部的控制,状态的跳转是通过状态的业务逻辑控制的,是自驱动的,那如何让外部业务逻辑来驱动状态跳转呢?这一问题将在下一篇文章中介绍。

 

标签:case,状态,Handle,StateType,stateMachine,void,模式,state
来源: https://www.cnblogs.com/fastexpress/p/16094609.html