首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >状态机无状态代码与传统的if-else代码相比,很难理解其好处。

状态机无状态代码与传统的if-else代码相比,很难理解其好处。
EN

Stack Overflow用户
提问于 2019-05-12 10:25:07
回答 1查看 6.2K关注 0票数 2

我最近遇到了一个脏的if-else代码,所以我寻找了一个重构选项,并找到了关于state-machine的建议,作为脏if-else代码的优雅替代。但我很难理解:作为客户,我有责任将机器从一种状态转移到另一种状态。现在,如果有两个转换选项(取决于在当前状态下完成的工作的结果),我还需要使用if -否则吗?如果是的话,这种模式的主要好处是什么?从我的观点来看,机器可以从启动状态自动完成转换。

在问我之前,我读过下面的文章,这只会强化我的观点:

Auto advancing state machine with Stateless

How to encapsulate .NET Stateless state machine

Statemachine that transitions to target state and fires transitions and states between?

在我的例子中,我有一个需要存储在Redis中的MarketPriceEvent。在存储之前,它必须通过验证路径。验证路径状态为:

  • 基本验证
  • 比较
  • 另一种比较
  • 储物
  • 错误审计

问题是我有很多决定要做。例如:只有BasicValidation成功通过,我才想迁移到Comparison。现在,如果Comparison成功了,我想迁移到Storing,否则移到ErrorAuditing。所以如果我们要进入密码:

代码语言:javascript
复制
 _machine.Configure(State.Validate).PermitIf(Trigger.Validated, State.Compare1, () => isValid);

        _machine.Configure(State.Compare1).OnEntry(CompareWithResource1).
            PermitIf(Trigger.Compared, State.Store, () => isValid)
            .PermitIf(Trigger.Compared, State.Compare2, () => !isValid);

在我的客户机/包装代码中,我将编写:

代码语言:javascript
复制
//Stay at Validate state
        var marketPriceProcessingMachine = new MarketPriceProcessingMachine();

        if (marketPriceProcessingMachine.Permitted(Trigger.Validated))
                       marketPriceProcessingMachine.Fire(Trigger.Validated);
        //else 
        // ...

简而言之,如果我需要使用if-else,我从这样的状态机概念中得到了什么好处?如果它是确定性的,为什么它不自我移动到下一个状态?如果我错了,怎么回事?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-05-13 05:59:53

使用状态机的好处之一是减少了对象所处的状态数。我和一个班里有22面旗的人一起工作。有很多如果!(一些东西&& !somethingElse !userClicked)…

这类代码很难读、很难调试、很难进行单元测试,并且或多或少不可能对类的实际状态进行推理。22个bool标志意味着这个类可以处于400多万个州。试着做单元测试..。

状态机可以降低代码的复杂性,但在新项目开始时,它几乎总是会使代码变得更加复杂。然而,从长远来看,我发现总体的复杂性最终是整体较低的。这是因为扩展和添加更多的状态很容易,因为已经定义的状态可以单独使用。

多年来,我发现OOP和状态机通常是相同的两个方面。我还发现OOP很难,很难“正确”。

我认为状态机不应该对对象的外部可见,包括它的触发器。您很可能希望拥有一个公共的只读状态属性。

在设计类时,调用方不能直接更改状态,也不能让调用方直接调用Fire方法。相反,我使用的方法是作为动作的谓词,如Validate()。

你的工作流程需要条件,但你有一些自由,把它们放在哪里。我建议将业务逻辑与状态机配置分离。我认为这使得状态机更容易阅读。

像这样的事怎么样:

代码语言:javascript
复制
namespace ConsoleApp1
{
    using Stateless;
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Press Q to stop validating events");
            ConsoleKeyInfo c;

            do
            {
                var mpe = new MarketPriceEvent();
                mpe.Validate();
                c = Console.ReadKey();

            } while (c.Key != ConsoleKey.Q);
        }
    }

    public class MarketPriceEvent
    {
        public void Validate()
        {
            _machine.Fire(Trigger.Validate);
        }

        public enum State { Validate, Compare2, ErrorAuditing, Compare1, Storing }
        private enum Trigger { Validate, CompareOneOk, CompareTwoOk, Error, }

        private readonly StateMachine<State, Trigger> _machine;
        public MarketPriceEvent()
        {
            _machine = new StateMachine<State, Trigger>(State.Validate);

            _machine.Configure(State.Validate)
                .Permit(Trigger.Validate, State.Compare1);

            _machine.Configure(State.Compare1)
                .OnEntry(DoEventValidation)
                .Permit(Trigger.CompareOneOk, State.Compare2)
                .Permit(Trigger.Error, State.ErrorAuditing);

            _machine.Configure(State.Compare2)
                .OnEntry(DoEventValidationAgainstResource2)
                .Permit(Trigger.CompareTwoOk, State.Storing)
                .Permit(Trigger.Error, State.ErrorAuditing);

            _machine.Configure(State.Storing)
                .OnEntry(HandleStoring);

            _machine.Configure(State.ErrorAuditing)
                .OnEntry(HandleError);
        }

        private void DoEventValidation()
        {
            // Business logic goes here
            if (isValid())
                _machine.Fire(Trigger.CompareOneOk);
            else
                _machine.Fire(Trigger.Error);
        }

        private void DoEventValidationAgainstResource2()
        {
            // Business logic goes here
            if (isValid())
                _machine.Fire(Trigger.CompareTwoOk);
            else
                _machine.Fire(Trigger.Error);
        }
        private bool isValid()
        {
            // Returns false every five seconds...
            return (DateTime.UtcNow.Second % 5) != 0;
        }

        private void HandleStoring()
        {
            Console.WriteLine("Awesome, validation OK!");
        }

        private void HandleError()
        {
            Console.WriteLine("Oh noes, validation failed!");
        }

    }
}
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56098282

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档